diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/CodeCoverage.runsettings b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/CodeCoverage.runsettings
index 4bfc5f9..ff2c2e1 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/CodeCoverage.runsettings
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/CodeCoverage.runsettings
@@ -6,7 +6,7 @@
cobertura,opencover
[*]Dataverse.ConfigurationMigrationTool.Console.Services.Dataverse.Connection.*,[*]Dataverse.ConfigurationMigrationTool.Console.Services.Dataverse.Configuration.*
- **/Program.cs,
+ **/Program.cs,**/IServiceCollectionExtensions.cs
true
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeBuilders/FakeEntityMetadataBuilder.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeBuilders/FakeEntityMetadataBuilder.cs
index 341125f..1243b1a 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeBuilders/FakeEntityMetadataBuilder.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeBuilders/FakeEntityMetadataBuilder.cs
@@ -35,6 +35,8 @@ public FakeEntityMetadataBuilder AddRelationship(string SchemaName, string Targe
{
Entity1LogicalName = EntityName,
Entity2LogicalName = TargetEntity,
+ Entity1IntersectAttribute = $"{EntityName}id",
+ Entity2IntersectAttribute = $"{TargetEntity}id",
IntersectEntityName = SchemaName,
SchemaName = SchemaName
};
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeDatasets.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeDatasets.cs
index a8eee6c..b6153ea 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeDatasets.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeDatasets.cs
@@ -1,4 +1,4 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
namespace Dataverse.ConfigurationMigrationTool.Console.Tests;
internal static class FakeDatasets
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeSchemas.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeSchemas.cs
index 701b595..05bd27b 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeSchemas.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/FakeSchemas.cs
@@ -1,4 +1,4 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
namespace Dataverse.ConfigurationMigrationTool.Console.Tests;
internal static class FakeSchemas
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/Commands/ExportCommandTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/Commands/ExportCommandTests.cs
new file mode 100644
index 0000000..0d519c1
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/Commands/ExportCommandTests.cs
@@ -0,0 +1,77 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Export;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Export.Commands;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using NSubstitute;
+using Shouldly;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Export.Commands;
+public class ExportCommandTests
+{
+ private readonly ILogger _logger;
+ private readonly ExportCommandOption _options = new ExportCommandOption();
+ private readonly IOptions _optionsWrapper;
+ private readonly IValidator _schemaValidator;
+ private readonly IFileDataService _fileDataService;
+ private readonly IDataExportService _dataExportService;
+ private readonly ExportCommand _exportCommand;
+ public ExportCommandTests()
+ {
+ _logger = Substitute.For>();
+ _optionsWrapper = Substitute.For>();
+ _optionsWrapper.Value.Returns(_options);
+ _schemaValidator = Substitute.For>();
+ _fileDataService = Substitute.For();
+ _dataExportService = Substitute.For(); ;
+ _exportCommand = new ExportCommand(_logger, _optionsWrapper, _schemaValidator, _fileDataService, _dataExportService);
+ }
+
+ [Fact]
+ public async Task GivenACommand_WhenItExecutesWithASchema_ThenItShouldExportData()
+ {
+ // Arrange
+ _options.schema = "schema.json";
+ _options.output = "output.json";
+
+ var schema = new DataSchema();
+ _fileDataService.ReadAsync(_options.schema).Returns(Task.FromResult(schema));
+ var validationResult = new ValidationResult();
+ _schemaValidator.Validate(schema).Returns(Task.FromResult(validationResult));
+ var entities = new List
+ {
+ new EntityImport { Name = "TestEntity", Displayname = "Test Entity" }
+ };
+ _dataExportService.ExportEntitiesFromSchema(schema).Returns(Task.FromResult(entities.AsEnumerable()));
+ // Act
+ await _exportCommand.Execute();
+ // Assert
+ await _fileDataService.Received(1).WriteAsync(Arg.Is(e => e.Entity.Count == 1), _options.output);
+ }
+ [Fact]
+ public async Task GivenACommand_WhenItExecutesWithAnInvalidSchema_ThenItShouldThrowError()
+ {
+ // Arrange
+ _options.schema = "schema.json";
+ _options.output = "output.json";
+
+ var schema = new DataSchema();
+ _fileDataService.ReadAsync(_options.schema).Returns(Task.FromResult(schema));
+ var validationResult = new ValidationResult()
+ {
+ Failures = [new("Test", "property failure")]
+ };
+ _schemaValidator.Validate(schema).Returns(Task.FromResult(validationResult));
+ var entities = new List
+ {
+ new EntityImport { Name = "TestEntity", Displayname = "Test Entity" }
+ };
+ _dataExportService.ExportEntitiesFromSchema(schema).Returns(Task.FromResult(entities.AsEnumerable()));
+ // Act
+ var ex = await _exportCommand.Execute().ShouldThrowAsync();
+ // Assert
+ ex.Message.ShouldBe("Provided Schema was not valid.");
+ }
+
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/DataExportServiceTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/DataExportServiceTests.cs
new file mode 100644
index 0000000..7373be6
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/DataExportServiceTests.cs
@@ -0,0 +1,92 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Export;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Extensions.Logging;
+using NSubstitute;
+using Shouldly;
+using Record = Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain.Record;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Export;
+public class DataExportServiceTests
+{
+ private readonly ILogger _logger;
+ private readonly IMetadataService _metadataService;
+ private readonly IDomainService _domainService;
+ private readonly DataExportService _dataExportService;
+
+ public DataExportServiceTests()
+ {
+ _logger = Substitute.For>();
+ _metadataService = Substitute.For();
+ _domainService = Substitute.For();
+ _dataExportService = new DataExportService(_logger, _metadataService, _domainService);
+ }
+ [Fact]
+ public async Task GivenADataExportService_WhenItExportsDataFromSchema_ThenItShouldUseDomainServiceProperly()
+ {
+ //Arrange
+
+ var schema = FakeSchemas.Contact;
+ var metadata = FakeMetadata.Contact;
+ _metadataService.GetEntity(metadata.LogicalName).Returns(metadata);
+
+ var records = new List
+ {
+ new()
+ {
+ Id = Guid.NewGuid(),
+ Field = [new(){
+ Name = "firstname",
+ Value = "John"
+ },
+ new(){
+ Name = "lastname",
+ Value = "Doe"
+ }],
+ },
+ new()
+ {
+ Id = Guid.NewGuid(),
+ Field = [new(){
+ Name = "firstname",
+ Value = "Jane"
+ },
+ new(){
+ Name = "lastname",
+ Value = "Dane"
+ }],
+ }
+ };
+ var rels = new List
+ {
+ new()
+ {
+ M2mrelationshipname = "contact_opportunities",
+ Sourceid = Guid.NewGuid(),
+ Targetentityname = "opportunity",
+ Targetentitynameidfield = "opportunityid",
+ Targetids = new Targetids
+ {
+ Targetid = [Guid.NewGuid(), Guid.NewGuid()]
+ }
+ }
+ };
+
+ _domainService.GetRecords(schema).Returns(records);
+ _domainService.GetM2mRelationships(metadata.ManyToManyRelationships.First())
+ .Returns(rels);
+
+ //Act
+ var result = await _dataExportService.ExportEntitiesFromSchema(new DataSchema
+ {
+ Entity = [schema]
+ });
+ //Assert
+ var entityImport = result.Single();
+ entityImport.Name.ShouldBe(schema.Name);
+ entityImport.Displayname.ShouldBe(schema.Displayname);
+ entityImport.Records.Record.ShouldBe(records);
+ entityImport.M2mrelationships.M2mrelationship.ShouldBe(rels, true);
+ }
+
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/Mappers/DataverseRecordToRecordMapperTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/Mappers/DataverseRecordToRecordMapperTests.cs
new file mode 100644
index 0000000..eba0964
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/Mappers/DataverseRecordToRecordMapperTests.cs
@@ -0,0 +1,35 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Export.Mappers;
+using Microsoft.Xrm.Sdk;
+using Shouldly;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Export.Mappers;
+public class DataverseRecordToRecordMapperTests
+{
+ private readonly DataverseRecordToRecordMapper _mapper = new DataverseRecordToRecordMapper();
+ [Fact]
+ public void GivenAnEntity_WhenItIsMappedToARecord_ThenItTheRecordShouldBeProperplyCreated()
+ {
+ //Arrange
+ var Schema = FakeSchemas.Account;
+ var Entity = new Entity("account")
+ {
+ Id = Guid.NewGuid(),
+ ["name"] = "Test Account",
+ ["primarycontactid"] = new EntityReference("contact", Guid.NewGuid())
+ };
+ //Act
+ var record = _mapper.Map((Schema, Entity));
+ //Assert
+ record.Id.ShouldBe(Entity.Id);
+ record.Field.ForEach(field =>
+ {
+ field.ShouldNotBeNull();
+ Entity.Attributes.Keys.ShouldContain(field.Name);
+ });
+ record.Field.First(f => f.Name == "name").Value.ShouldBe("Test Account");
+ var lookupField = record.Field.First(f => f.Name == "primarycontactid");
+ lookupField.Value.ShouldBe(Entity.GetAttributeValue("primarycontactid").Id.ToString());
+ lookupField.Lookupentity.ShouldBe("contact");
+ lookupField.Lookupentityname.ShouldBeNull();
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/Mappers/EntityFieldValueToFieldMapperTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/Mappers/EntityFieldValueToFieldMapperTests.cs
new file mode 100644
index 0000000..2e6dac2
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Export/Mappers/EntityFieldValueToFieldMapperTests.cs
@@ -0,0 +1,83 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Export.Mappers;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Xrm.Sdk;
+using Shouldly;
+using System.Web;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Export.Mappers;
+public class EntityFieldValueToFieldMapperTests
+{
+ private readonly EntityFieldValueToFieldMapper _mapper = new EntityFieldValueToFieldMapper();
+ private static readonly DateTime CurrentDate = DateTime.UtcNow;
+ private static readonly Guid RandomGuid = Guid.NewGuid();
+ public static TheoryData TestData => new TheoryData
+ {
+ {
+ new FieldSchema { Name = "testField" },
+ null,
+ null
+ },
+ {
+ new FieldSchema { Name = "testLookupField" },
+ new EntityReference("testEntity", RandomGuid),
+ new Field { Name = "testLookupField", Lookupentity = "testEntity", Value = RandomGuid.ToString() }
+ },
+ {
+ new FieldSchema { Name = "testOptionSetField" },
+ new OptionSetValue(1),
+ new Field { Name = "testOptionSetField", Value = "1" }
+ },
+ {
+ new FieldSchema { Name = "testBooleanField" },
+ true,
+ new Field { Name = "testBooleanField", Value = "True" }
+ },
+ {
+ new FieldSchema { Name = "testDateTimeField" },
+ CurrentDate,
+ new Field { Name = "testDateTimeField", Value = CurrentDate.ToString("o") }
+ },
+ {
+ new FieldSchema { Name = "testGuidField" },
+ RandomGuid,
+ new Field { Name = "testGuidField", Value = RandomGuid.ToString() }
+ },
+ {
+ new FieldSchema { Name = "testMoneyField" },
+ new Money(100.50m),
+ new Field { Name = "testMoneyField", Value = "100.50" }
+ },
+ {
+ new FieldSchema { Name = "testDecimalField" },
+ 123.45m,
+ new Field { Name = "testDecimalField", Value = "123.45" }
+ },
+ {
+ new FieldSchema { Name = "testDoubleField" },
+ 123.456789,
+ new Field { Name = "testDoubleField", Value = "123.456789" }
+ },
+ {
+ new FieldSchema { Name = "testStringField" },
+ "<>Root<>''/",
+ new Field { Name = "testStringField", Value = HttpUtility.HtmlEncode("<>Root<>''/") }
+ }
+ };
+
+ [Theory]
+ [MemberData(nameof(TestData))]
+ public void GivenAnAttributeValue_WhenItIsMappedToAField_ThenFieldShouldBeCreatedProperly(FieldSchema schema, object value, Field expected)
+ {
+ // Act
+ var result = _mapper.Map((schema, value));
+ // Assert
+ if (expected == null)
+ {
+ result.ShouldBeNull();
+ }
+ else
+ {
+ result.ShouldBeEquivalentTo(expected);
+ }
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Commands/ImportCommandsTest.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Commands/ImportCommandsTest.cs
index 1df1f05..722186c 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Commands/ImportCommandsTest.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Commands/ImportCommandsTest.cs
@@ -2,6 +2,7 @@
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Commands;
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Dataverse.ConfigurationMigrationTool.Console.Tests.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -13,7 +14,7 @@ public class ImportCommandsTest
{
private readonly ILogger _logger;
private readonly IImportDataProvider _importDataProvider;
- private readonly IValidator _schemaValidator;
+ private readonly IValidator _schemaValidator;
private readonly IImportTaskProcessorService _importDataService;
private readonly ImportCommands _importCommands;
const string DataFilePath = "data.json";
@@ -28,7 +29,7 @@ public ImportCommandsTest()
{
_logger = Substitute.For>();
_importDataProvider = Substitute.For();
- _schemaValidator = Substitute.For>();
+ _schemaValidator = Substitute.For>();
_importDataService = Substitute.For();
var options = Substitute.For>();
options.Value.Returns(_options);
@@ -43,7 +44,7 @@ public ImportCommandsTest()
public async Task GivenDataToImportWithSchema_WhenTheCommandExecutes_ThenItShouldProcessImportsAccordingly()
{
//Arrange
- var importSchema = new ImportSchema
+ var importSchema = new DataSchema
{
Entity = new()
{
@@ -84,7 +85,7 @@ public async Task GivenDataToImportWithSchema_WhenTheCommandExecutes_ThenItShoul
public async Task GivenDataToImportWithSchema_WhenTheCommandExecutesAndFails_ThenItShouldThrowAnError()
{
//Arrange
- var importSchema = new ImportSchema
+ var importSchema = new DataSchema
{
Entity = new()
{
@@ -122,7 +123,7 @@ public async Task GivenDataToImportWithSchema_WhenTheCommandExecutesAndFails_The
public async Task GivenAnInvalidSchema_WhenTheCommandExecutes_ThenItShouldFailAndLogIssues()
{
//Arrange
- var importSchema = new ImportSchema
+ var importSchema = new DataSchema
{
Entity = new()
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/ImportTaskProcessorServiceTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/ImportTaskProcessorServiceTests.cs
index 333607c..ce456a0 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/ImportTaskProcessorServiceTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/ImportTaskProcessorServiceTests.cs
@@ -3,6 +3,7 @@
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.ValueConverters;
using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Dataverse.ConfigurationMigrationTool.Console.Services.Dataverse.Connection;
using Dataverse.ConfigurationMigrationTool.Console.Tests.Extensions;
using Dataverse.ConfigurationMigrationTool.Console.Tests.FakeBuilders;
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Mappers/FieldSchemaToAttributeTypeMapperTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Mappers/FieldSchemaToAttributeTypeMapperTests.cs
index 49fa70d..514f529 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Mappers/FieldSchemaToAttributeTypeMapperTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Mappers/FieldSchemaToAttributeTypeMapperTests.cs
@@ -1,5 +1,5 @@
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Mappers;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Microsoft.Xrm.Sdk.Metadata;
using Shouldly;
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/ValueConverters/DataverseValueConverterTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/ValueConverters/DataverseValueConverterTests.cs
index 938a96b..0109596 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/ValueConverters/DataverseValueConverterTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/ValueConverters/DataverseValueConverterTests.cs
@@ -1,5 +1,5 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.ValueConverters;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Import.ValueConverters;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Dataverse.ConfigurationMigrationTool.Console.Tests.FakeBuilders;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/EntitySchemaValidatorTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/EntitySchemaValidatorTests.cs
similarity index 92%
rename from src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/EntitySchemaValidatorTests.cs
rename to src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/EntitySchemaValidatorTests.cs
index 2be8437..340067a 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/EntitySchemaValidatorTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/EntitySchemaValidatorTests.cs
@@ -1,14 +1,14 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.RelationshipSchemas;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.RelationshipSchemas;
using Microsoft.Xrm.Sdk.Metadata;
using NSubstitute;
using Shouldly;
-namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Import.Validators.Rules.EntitySchemas;
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Shared.Validators.Rules.EntitySchemas;
public class EntitySchemaValidatorTests
{
private readonly IMetadataService metadataService = Substitute.For();
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/BaseFieldSchemaValidationRuleTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/BaseFieldSchemaValidationRuleTests.cs
similarity index 65%
rename from src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/BaseFieldSchemaValidationRuleTests.cs
rename to src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/BaseFieldSchemaValidationRuleTests.cs
index d51873a..bbe3bc0 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/BaseFieldSchemaValidationRuleTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/BaseFieldSchemaValidationRuleTests.cs
@@ -1,9 +1,9 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
using Microsoft.Xrm.Sdk.Metadata;
-namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas;
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
public abstract class BaseFieldSchemaValidationRuleTests where TRule : IFieldSchemaValidationRule
{
protected TMetadata CreateAttributeMetadata() where TMetadata : AttributeMetadata
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRuleTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRuleTests.cs
similarity index 91%
rename from src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRuleTests.cs
rename to src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRuleTests.cs
index a0aa0f0..c000c27 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRuleTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRuleTests.cs
@@ -1,9 +1,9 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
using Microsoft.Xrm.Sdk.Metadata;
using Shouldly;
-namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas;
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
public class FieldTypeMustMatchWithAttributeValidationRuleTests : BaseFieldSchemaValidationRuleTests
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRuleTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRuleTests.cs
similarity index 92%
rename from src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRuleTests.cs
rename to src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRuleTests.cs
index f28851e..145825e 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRuleTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRuleTests.cs
@@ -1,9 +1,9 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
using Microsoft.Xrm.Sdk.Metadata;
using Shouldly;
-namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas;
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
public class LookupFieldsTargetsMustMatchValidationRuleTests :
BaseFieldSchemaValidationRuleTests
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRuleTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRuleTests.cs
similarity index 86%
rename from src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRuleTests.cs
rename to src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRuleTests.cs
index db04d2e..4ad4319 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRuleTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRuleTests.cs
@@ -1,9 +1,9 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.RelationshipSchemas;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.RelationshipSchemas;
using Microsoft.Xrm.Sdk.Metadata;
using Shouldly;
-namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Import.Validators.Rules.EntitySchemas.RelationshipSchemas;
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Shared.Validators.Rules.EntitySchemas.RelationshipSchemas;
public class SourceEntityNameMustMatchValidationRuleTests
{
private readonly SourceEntityNameMustMatchValidationRule _rule = new();
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRuleTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRuleTests.cs
similarity index 86%
rename from src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRuleTests.cs
rename to src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRuleTests.cs
index f114d5e..7e7c1db 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRuleTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRuleTests.cs
@@ -1,9 +1,9 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.RelationshipSchemas;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.RelationshipSchemas;
using Microsoft.Xrm.Sdk.Metadata;
using Shouldly;
-namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Import.Validators.Rules.EntitySchemas.RelationshipSchemas;
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Shared.Validators.Rules.EntitySchemas.RelationshipSchemas;
public class TargetEntityNameMustMatchValidationRuleTests
{
private readonly TargetEntityNameMustMatchValidationRule _rule = new();
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/SchemaValidatorTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/SchemaValidatorTests.cs
similarity index 77%
rename from src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/SchemaValidatorTests.cs
rename to src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/SchemaValidatorTests.cs
index fb8cae6..45c3394 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Validators/Rules/SchemaValidatorTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Shared/Validators/Rules/SchemaValidatorTests.cs
@@ -1,14 +1,14 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators;
using NSubstitute;
using Shouldly;
-namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Import.Validators.Rules;
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features.Shared.Validators.Rules;
public class SchemaValidatorTests
{
private readonly IValidator entityValidator = Substitute.For>();
- private readonly IValidator validator;
+ private readonly IValidator validator;
public SchemaValidatorTests()
{
validator = new SchemaValidator(entityValidator);
@@ -18,7 +18,7 @@ public SchemaValidatorTests()
public async Task GivenValidSchema_WhenValidated_ThenShouldReturnSuccess()
{
// Arrange
- var schema = new ImportSchema
+ var schema = new DataSchema
{
Entity = new List
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Dataverse/DataverseDomainServiceTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Dataverse/DataverseDomainServiceTests.cs
new file mode 100644
index 0000000..3cc6d3c
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Dataverse/DataverseDomainServiceTests.cs
@@ -0,0 +1,127 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Services.Dataverse;
+using Dataverse.ConfigurationMigrationTool.Console.Tests.Extensions;
+using Microsoft.Extensions.Logging;
+using Microsoft.PowerPlatform.Dataverse.Client;
+using Microsoft.Xrm.Sdk;
+using Microsoft.Xrm.Sdk.Query;
+using NSubstitute;
+using Shouldly;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Services.Dataverse;
+public class DataverseDomainServiceTests
+{
+ private readonly IOrganizationServiceAsync2 _orgService;
+ private readonly ILogger _logger;
+ private readonly DataverseDomainService _domainService;
+ public DataverseDomainServiceTests()
+ {
+ _orgService = Substitute.For();
+ _logger = Substitute.For>();
+ _domainService = new DataverseDomainService(_orgService, _logger);
+ }
+ [Fact]
+ public async Task GivenADomainService_WhenItExportsWithEntitySchema_ThenItShouldCallDataverseProperly()
+ {
+ //Arrange
+ var schema = FakeSchemas.Account;
+ var primaryContactField = new EntityReference("contact", Guid.NewGuid()) { Name = "John Doe" };
+ var firstPage = new EntityCollection
+ {
+ MoreRecords = true
+ };
+ firstPage.Entities.Add(new(schema.Name)
+ {
+ Id = Guid.NewGuid(),
+ ["name"] = "Test Account",
+ ["primarycontactid"] = primaryContactField
+ });
+ var secondPage = new EntityCollection()
+ {
+ MoreRecords = false
+ };
+ secondPage.Entities.Add(new(schema.Name)
+ {
+ Id = Guid.NewGuid(),
+ ["name"] = "Test2 Account",
+ ["primarycontactid"] = primaryContactField
+ });
+ _orgService.RetrieveMultipleAsync(Arg.Any(), Arg.Any())
+ .Returns(r =>
+ {
+
+ var arg = r.Arg();
+ if (arg.PageInfo.PageNumber == 1)
+ {
+ return Task.FromResult(firstPage);
+ }
+ else
+ {
+ return Task.FromResult(secondPage);
+ }
+ });
+
+ //Act
+ var result = (await _domainService.GetRecords(schema)).ToList();
+
+ //Assert
+ result.Count.ShouldBe(2);
+ result[0].Id.ShouldBe(firstPage.Entities[0].Id);
+ result[0].Field.ShouldContain(f => f.Name == "name" && f.Value.ToString() == "Test Account");
+ result[0].Field.ShouldContain(f => f.Name == "primarycontactid" &&
+ f.Value == primaryContactField.Id.ToString()
+ && f.Lookupentityname == primaryContactField.Name
+ && f.Lookupentity == primaryContactField.LogicalName);
+ result[1].Id.ShouldBe(secondPage.Entities[0].Id);
+ result[1].Field.ShouldContain(f => f.Name == "name" && f.Value.ToString() == "Test2 Account");
+ result[1].Field.ShouldContain(f => f.Name == "primarycontactid" &&
+ f.Value == primaryContactField.Id.ToString()
+ && f.Lookupentityname == primaryContactField.Name
+ && f.Lookupentity == primaryContactField.LogicalName);
+ }
+ [Fact]
+ public async Task GivenADomainService_WhenItExportsWithEntitySchemaWithNoFields_ThenItShouldNotCallDataverse()
+ {
+ //Arrange
+ var schema = new EntitySchema()
+ {
+ Name = "account",
+ };
+
+ //Act
+ var result = await _domainService.GetRecords(schema);
+
+ //Assert
+ result.ShouldBeEmpty();
+ _logger.ShouldHaveLogged(LogLevel.Warning, $"No fields specified for export in schema for entity {schema.Name}");
+
+ }
+ [Fact]
+ public async Task GivenADomainService_WhenItExportsM2mRelationships_ThenItShouldCallDataverseProperly()
+ {
+ //Arrange
+ var metadata = FakeMetadata.Contact;
+ var m2mMetadata = metadata.ManyToManyRelationships.First();
+ var response = new EntityCollection();
+ response.Entities.Add(new(m2mMetadata.IntersectEntityName)
+ {
+ Id = Guid.NewGuid(),
+ [m2mMetadata.Entity1IntersectAttribute] = Guid.NewGuid(),
+ [m2mMetadata.Entity2IntersectAttribute] = Guid.NewGuid()
+ });
+
+ _orgService.RetrieveMultipleAsync(Arg.Any(), Arg.Any())
+ .Returns(response);
+ //Act
+ var result = (await _domainService.GetM2mRelationships(m2mMetadata)).ToList();
+ //Assert
+ result.Count.ShouldBe(1);
+ var entity = response.Entities[0];
+ result[0].Sourceid.ShouldBe(entity.GetAttributeValue(m2mMetadata.Entity1IntersectAttribute));
+ result[0].Targetentityname.ShouldBe(m2mMetadata.Entity2LogicalName);
+ result[0].Targetentitynameidfield.ShouldBe(m2mMetadata.Entity2IntersectAttribute);
+ result[0].Targetids.Targetid.Count.ShouldBe(1);
+ result[0].Targetids.Targetid[0].ShouldBe(entity.GetAttributeValue(m2mMetadata.Entity2IntersectAttribute));
+
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Filesystem/FileReaderDataImportProviderTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Filesystem/FileReaderDataImportProviderTests.cs
index 6f00c75..ab4f3f8 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Filesystem/FileReaderDataImportProviderTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Filesystem/FileReaderDataImportProviderTests.cs
@@ -1,4 +1,5 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Dataverse.ConfigurationMigrationTool.Console.Services.Filesystem;
using Microsoft.Extensions.Logging;
using NSubstitute;
@@ -7,11 +8,11 @@
namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Services.Filesystem;
public class FileReaderDataImportProviderTests
{
- private readonly IFileDataReader _dataReader;
+ private readonly IFileDataService _dataReader;
private readonly FileReaderDataImportProvider _fileReaderDataImportProvider;
public FileReaderDataImportProviderTests()
{
- _dataReader = Substitute.For();
+ _dataReader = Substitute.For();
_fileReaderDataImportProvider = new FileReaderDataImportProvider(_dataReader,
Substitute.For>());
@@ -21,13 +22,13 @@ public async Task GivenAnImportSchema_WhenProviderReadsTheImportSchema_ThenItSho
{
// Arrange
var filePath = "test-schema.json";
- var importSchema = new ImportSchema();
- _dataReader.ReadAsync(filePath).Returns(importSchema);
+ var importSchema = new DataSchema();
+ _dataReader.ReadAsync(filePath).Returns(importSchema);
// Act
var result = await _fileReaderDataImportProvider.ReadSchemaFromFile(filePath);
// Assert
result.ShouldBe(importSchema);
- await _dataReader.Received(1).ReadAsync(filePath);
+ await _dataReader.Received(1).ReadAsync(filePath);
}
[Fact]
public async Task GivenAnEntityImport_WhenProviderReadsTheEntityData_ThenItShouldUseDataReader()
diff --git a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Filesystem/XmlFileDataReaderTests.cs b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Filesystem/XmlFileDataReaderTests.cs
index b0e3bfe..a5ec690 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Filesystem/XmlFileDataReaderTests.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Console.Tests/Services/Filesystem/XmlFileDataReaderTests.cs
@@ -1,4 +1,4 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Dataverse.ConfigurationMigrationTool.Console.Services.Filesystem;
using Shouldly;
@@ -12,7 +12,7 @@ public async Task GivenAnXmlFile_WhenTheDataReaderReadsIt_ThenItShouldReturnData
// Arrange
var filePath = "assets/schema.xml"; // Path to your test XML file
// Act
- var result = await _xmlFileDataReader.ReadAsync(filePath);
+ var result = await _xmlFileDataReader.ReadAsync(filePath);
// Assert
result.ShouldNotBeNull();
var entity = result.Entity.First();
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Common/IOrganizationServiceExtensions.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Common/IOrganizationServiceExtensions.cs
new file mode 100644
index 0000000..a16105b
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Common/IOrganizationServiceExtensions.cs
@@ -0,0 +1,42 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.PowerPlatform.Dataverse.Client;
+using Microsoft.Xrm.Sdk;
+using Microsoft.Xrm.Sdk.Query;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Common;
+public static class IOrganizationServiceExtensions
+{
+ public static async Task RetrieveAll(this IOrganizationServiceAsync2 service, QueryExpression query, int page = 5000, ILogger _logger = null, CancellationToken cancellationToken = default)
+ {
+ // The records to return
+ List entities = new();
+
+ // Set the page
+ query.PageInfo.PageNumber = 1;
+ // Set the count
+ query.PageInfo.Count = page;
+
+ while (true)
+ {
+ _logger?.LogInformation("Retrieving page {page} with {count} records", query.PageInfo.PageNumber, query.PageInfo.Count);
+ // Get the records
+ var results = await service.RetrieveMultipleAsync(query, cancellationToken);
+
+ entities.AddRange(results.Entities);
+ _logger?.LogInformation("Retrieved {count} records from page {page}", results.Entities.Count, query.PageInfo.PageNumber);
+ _logger?.LogInformation("Total Retrieved {count} records", entities.Count);
+ if (!results.MoreRecords)
+ {
+ //Stop if there are no more records
+ break;
+ }
+ // Set the PagingCookie with the PagingCookie from the previous query
+ query.PageInfo.PagingCookie = results.PagingCookie;
+
+ // Update the PageNumber
+ query.PageInfo.PageNumber++;
+ }
+
+ return new EntityCollection(entities);
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Commands/ExportCommand.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Commands/ExportCommand.cs
new file mode 100644
index 0000000..43537a9
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Commands/ExportCommand.cs
@@ -0,0 +1,57 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Export.Commands;
+[CommandVerb("export-data")]
+public class ExportCommand : ICommand
+{
+ private readonly ILogger _logger;
+ private readonly ExportCommandOption _options;
+ private readonly IValidator _schemaValidator;
+ private readonly IFileDataService _fileDataService;
+ private readonly IDataExportService _dataExportService;
+
+ public ExportCommand(ILogger logger,
+ IOptions options,
+ IValidator schemaValidator,
+ IFileDataService fileDataReader,
+ IDataExportService dataExportService)
+ {
+ _logger = logger;
+ _options = options.Value;
+ _schemaValidator = schemaValidator;
+ _fileDataService = fileDataReader;
+ _dataExportService = dataExportService;
+ }
+
+ public async Task Execute() => await Export(_options.schema, _options.output);
+
+ private async Task Export(string schemafilepath, string outputfilepath)
+ {
+
+ _logger.LogInformation("Parsing schema file from arguments");
+ var schema = await _fileDataService.ReadAsync(schemafilepath);
+
+ var schemaValidationResult = await _schemaValidator.Validate(schema);
+ if (schemaValidationResult.IsError)
+ {
+ _logger.LogError("Schema failed validation process with {count} failure(s).", schemaValidationResult.Failures.Count);
+ foreach (var failure in schemaValidationResult.Failures)
+ {
+ _logger.LogError("schema validation failure: {property} => {failure}", failure.PropertyBound, failure.Message);
+ }
+ throw new Exception("Provided Schema was not valid.");
+ }
+ _logger.LogInformation("Schema validation succeeded.");
+
+ var entities = await _dataExportService.ExportEntitiesFromSchema(schema);
+ var wrapper = new Entities
+ {
+ Entity = entities.ToList()
+ };
+ await _fileDataService.WriteAsync(wrapper, outputfilepath);
+ }
+
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Commands/ExportCommandOption.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Commands/ExportCommandOption.cs
new file mode 100644
index 0000000..5f04c26
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Commands/ExportCommandOption.cs
@@ -0,0 +1,6 @@
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Export.Commands;
+public class ExportCommandOption
+{
+ public string schema { get; set; }
+ public string output { get; set; }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/DataExportService.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/DataExportService.cs
new file mode 100644
index 0000000..4e2ad36
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/DataExportService.cs
@@ -0,0 +1,61 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Extensions.Logging;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Export;
+public interface IDataExportService
+{
+ Task> ExportEntitiesFromSchema(DataSchema Schema);
+}
+public class DataExportService : IDataExportService
+{
+ private readonly ILogger _logger;
+ private readonly IMetadataService _metadataService;
+ private readonly IDomainService _domainService;
+
+ public DataExportService(ILogger logger,
+ IMetadataService metadataService,
+ IDomainService domainService)
+ {
+ _logger = logger;
+ _metadataService = metadataService;
+ _domainService = domainService;
+ }
+
+ public async Task> ExportEntitiesFromSchema(DataSchema Schema)
+ {
+ var entityImports = new Dictionary();
+ foreach (var entitySchema in Schema.Entity)
+ {
+ _logger.LogInformation("Exporting entity {entityName}", entitySchema.Displayname);
+ var metadata = await _metadataService.GetEntity(entitySchema.Name);
+ var data = await _domainService.GetRecords(entitySchema);
+ //Add Relationships export
+ var entityRelationShips = new List();
+ foreach (var relationship in entitySchema.Relationships.Relationship)
+ {
+ if (!relationship.ManyToMany)
+ {
+ continue;
+ }
+ var relMD = metadata.ManyToManyRelationships.FirstOrDefault(r => r.IntersectEntityName == relationship.RelatedEntityName);
+ var relationships = await _domainService.GetM2mRelationships(relMD);
+ entityRelationShips.AddRange(relationships);
+
+ }
+ entityImports[entitySchema.Name] = new EntityImport
+ {
+ Name = entitySchema.Name,
+ Displayname = entitySchema.Displayname,
+ Records = new Records { Record = data.ToList() },
+ M2mrelationships = new M2mrelationships
+ {
+ M2mrelationship = entityRelationShips
+ }
+ };
+
+ }
+ // Write To File
+ return entityImports.Select(kv => kv.Value).ToList();
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/IDomainService.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/IDomainService.cs
new file mode 100644
index 0000000..26a1f54
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/IDomainService.cs
@@ -0,0 +1,11 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Xrm.Sdk.Metadata;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Export;
+public interface IDomainService
+{
+ Task> GetRecords(EntitySchema Schema);
+ Task> GetM2mRelationships(ManyToManyRelationshipMetadata metadata);
+
+
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/IServiceCollectionExtensions.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/IServiceCollectionExtensions.cs
new file mode 100644
index 0000000..0920064
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/IServiceCollectionExtensions.cs
@@ -0,0 +1,14 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Export.Commands;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Export;
+public static class IServiceCollectionExtensions
+{
+ public static IServiceCollection AddExportFeature(this IServiceCollection services, IConfiguration Configuration)
+ {
+ services.AddScoped()
+ .Configure(Configuration);
+ return services;
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Mappers/DataverseRecordToRecordMapper.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Mappers/DataverseRecordToRecordMapper.cs
new file mode 100644
index 0000000..9de8902
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Mappers/DataverseRecordToRecordMapper.cs
@@ -0,0 +1,34 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Xrm.Sdk;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Export.Mappers;
+public class DataverseRecordToRecordMapper : IMapper<(EntitySchema, Entity), Record>
+{
+ private readonly static IMapper<(FieldSchema, object), Field> _fieldMapper = new EntityFieldValueToFieldMapper();
+ public Record Map((EntitySchema, Entity) source)
+ {
+ var (entitySchema, entity) = source;
+ var record = new Record()
+ {
+ Id = entity.Id,
+ Field = new List()
+ };
+
+ foreach (var fieldSchema in entitySchema.Fields.Field)
+ {
+ if (entity.Contains(fieldSchema.Name))
+ {
+ var fieldValue = entity[fieldSchema.Name];
+ var field = _fieldMapper.Map((fieldSchema, fieldValue));
+ if (field == null)
+ {
+ continue;
+ }
+ record.Field.Add(field);
+ }
+ }
+ return record;
+ }
+}
+
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Mappers/EntityFieldValueToFieldMapper.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Mappers/EntityFieldValueToFieldMapper.cs
new file mode 100644
index 0000000..5960477
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Export/Mappers/EntityFieldValueToFieldMapper.cs
@@ -0,0 +1,66 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Xrm.Sdk;
+using System.Web;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Export.Mappers;
+public class EntityFieldValueToFieldMapper : IMapper<(FieldSchema, object), Field>
+{
+ public Field Map((FieldSchema, object) source)
+ {
+ var (fieldSchema, value) = source;
+ var fieldResult = new Field
+ {
+ Name = fieldSchema.Name,
+ };
+ if (value == null)
+ {
+ return null;
+ }
+ if (value is EntityReference reference)
+ {
+ fieldResult.Lookupentity = reference.LogicalName;
+ fieldResult.Lookupentityname = reference.Name;
+ fieldResult.Value = reference.Id.ToString();
+ return fieldResult;
+ }
+ if (value is OptionSetValue optionSetValue)
+ {
+ fieldResult.Value = optionSetValue.Value.ToString();
+ return fieldResult;
+ }
+ if (value is bool booleanValue)
+ {
+ fieldResult.Value = booleanValue ? "True" : "False";
+ return fieldResult;
+ }
+ if (value is DateTime dateTimeValue)
+ {
+ fieldResult.Value = dateTimeValue.ToString("o"); // ISO 8601 format
+ return fieldResult;
+ }
+ if (value is Guid guidValue)
+ {
+ fieldResult.Value = guidValue.ToString();
+ return fieldResult;
+ }
+ if (value is Money moneyValue)
+ {
+ fieldResult.Value = moneyValue.Value.ToString();
+ return fieldResult;
+ }
+ if (value is decimal decimalValue)
+ {
+ fieldResult.Value = decimalValue.ToString();
+ return fieldResult;
+ }
+ if (value is double doubleValue)
+ {
+ fieldResult.Value = doubleValue.ToString();
+ return fieldResult;
+ }
+ var str = value?.ToString() ?? string.Empty;
+ fieldResult.Value = HttpUtility.HtmlEncode(str);
+ return fieldResult;
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/IServiceCollectionExtensions.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/IServiceCollectionExtensions.cs
new file mode 100644
index 0000000..7abd7fc
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/IServiceCollectionExtensions.cs
@@ -0,0 +1,45 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Export;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Import;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.RelationshipSchemas;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System.Reflection;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features;
+public static class IServiceCollectionExtensions
+{
+ public static IServiceCollection AddConfigurationMigrationTool(this IServiceCollection services, IConfiguration Configuration)
+ {
+ return services
+ .AddSharedServices()
+ .AddImportFeature(Configuration)
+ .AddExportFeature(Configuration);
+ }
+ public static IServiceCollection AddSharedServices(this IServiceCollection services)
+ {
+ return services.RegisterFromReflection()
+ .RegisterFromReflection()
+ .AddTransient, SchemaValidator>()
+ .AddTransient, EntitySchemaValidator>();
+ }
+ public static IServiceCollection UseCommands(this IServiceCollection services, params string[] args)
+ {
+ services.AddSingleton>(Options.Create(new CommandProcessorHostingServiceOptions() { CommandVerb = args[0] }));
+ return services.AddHostedService();
+ }
+ public static IServiceCollection RegisterFromReflection(this IServiceCollection services)
+ {
+ var genericType = typeof(T);
+ var classes = Assembly.GetCallingAssembly().GetTypes()
+ .Where(type => genericType.IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract);
+ foreach (var c in classes)
+ services.AddTransient(genericType, c);
+ return services;
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Commands/ImportCommands.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Commands/ImportCommands.cs
index 82ac4e2..383aa62 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Commands/ImportCommands.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Commands/ImportCommands.cs
@@ -1,5 +1,6 @@
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -9,13 +10,13 @@ public class ImportCommands : ICommand
{
private readonly ILogger _logger;
private readonly IImportDataProvider _importDataProvider;
- private readonly IValidator _schemaValidator;
+ private readonly IValidator _schemaValidator;
private readonly IImportTaskProcessorService _importDataService;
private readonly ImportCommandOptions _options;
public ImportCommands(ILogger logger,
IImportDataProvider importDataProvider,
- IValidator schemaValidator,
+ IValidator schemaValidator,
IImportTaskProcessorService importDataService,
IOptions options)
{
@@ -90,7 +91,7 @@ private async Task> ProcessQueue(Queue I
}
return taskResults;
}
- private static Queue CreateQueue(ImportSchema schema)
+ private static Queue CreateQueue(DataSchema schema)
{
var ImportQueue = new Queue();
foreach (var schemaEntity in schema.Entity)
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/IImportDataProvider.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/IImportDataProvider.cs
index f8f0f37..d72e95d 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/IImportDataProvider.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/IImportDataProvider.cs
@@ -1,10 +1,10 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import
{
public interface IImportDataProvider
{
Task ReadFromFile(string filePath);
- Task ReadSchemaFromFile(string filePath);
+ Task ReadSchemaFromFile(string filePath);
}
}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/IServiceCollectionExtensions.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/IServiceCollectionExtensions.cs
index c5fc540..2303253 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/IServiceCollectionExtensions.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/IServiceCollectionExtensions.cs
@@ -1,15 +1,8 @@
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Commands;
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Interceptors;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.RelationshipSchemas;
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.ValueConverters;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Options;
using System.Reflection;
namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import;
@@ -19,8 +12,7 @@ public static class IServiceCollectionExtensions
public static IServiceCollection AddImportFeature(this IServiceCollection services, IConfiguration Configuration)
{
- return services.RegisterFromReflection()
- .RegisterFromReflection()
+ return services
.AddSingleton(_ =>
{
var valueConverterTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => !t.IsAbstract &&
@@ -28,8 +20,7 @@ public static IServiceCollection AddImportFeature(this IServiceCollection servic
return new ReflectionMainConverter(valueConverterTypes);
})
.AddSingleton()
- .AddTransient, SchemaValidator>()
- .AddTransient, EntitySchemaValidator>()
+
.AddSingleton()
.AddSingleton((sp) =>
{
@@ -48,18 +39,5 @@ public static T BuildService(this IServiceProvider serviceProvider) where T :
return ActivatorUtilities.CreateInstance(serviceProvider);
}
- public static IServiceCollection UseCommands(this IServiceCollection services, params string[] args)
- {
- services.AddSingleton>(Options.Create(new CommandProcessorHostingServiceOptions() { CommandVerb = args[0] }));
- return services.AddHostedService();
- }
- public static IServiceCollection RegisterFromReflection(this IServiceCollection services)
- {
- var genericType = typeof(T);
- var classes = Assembly.GetCallingAssembly().GetTypes()
- .Where(type => genericType.IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract);
- foreach (var c in classes)
- services.AddTransient(genericType, c);
- return services;
- }
+
}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ImportTaskProcessorService.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ImportTaskProcessorService.cs
index 887b135..ebc1dd5 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ImportTaskProcessorService.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ImportTaskProcessorService.cs
@@ -2,6 +2,7 @@
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.ValueConverters;
using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Dataverse.ConfigurationMigrationTool.Console.Services.Dataverse.Connection;
using Microsoft.Extensions.Logging;
using Microsoft.Xrm.Sdk;
@@ -10,12 +11,7 @@
namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import;
-public enum TaskResult
-{
- Completed,
- Failed,
- Requeue
-}
+
public interface IImportTaskProcessorService
{
Task Execute(ImportDataTask task, Entities dataImport);
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Mappers/FieldSchemaToAttributeTypeMapper.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Mappers/FieldSchemaToAttributeTypeMapper.cs
index 2f16db5..0a7d874 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Mappers/FieldSchemaToAttributeTypeMapper.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Mappers/FieldSchemaToAttributeTypeMapper.cs
@@ -1,5 +1,5 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Microsoft.Xrm.Sdk.Metadata;
namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Mappers;
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Model/ImportDataTask.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Model/ImportDataTask.cs
index 88790f6..3c43b8a 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Model/ImportDataTask.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Model/ImportDataTask.cs
@@ -1,4 +1,6 @@
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model
{
public class ImportDataTask
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/IFieldSchemaValidationRule.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/IFieldSchemaValidationRule.cs
deleted file mode 100644
index 5985278..0000000
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/IFieldSchemaValidationRule.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Microsoft.Xrm.Sdk.Metadata;
-
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas
-{
- public interface IFieldSchemaValidationRule
- {
- Task Validate(FieldSchema fieldSchema, AttributeMetadata attributeMetadata);
- }
-}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRule.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRule.cs
deleted file mode 100644
index d7a356b..0000000
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRule.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Dataverse.ConfigurationMigrationTool.Console.Common;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Microsoft.Xrm.Sdk.Metadata;
-
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas
-{
- public class LookupFieldsTargetsMustMatchValidationRule : IFieldSchemaValidationRule
- {
- public async Task Validate(FieldSchema fieldSchema, AttributeMetadata attributeMetadata)
- {
- if (attributeMetadata is LookupAttributeMetadata lookupMD &&
- lookupMD.AttributeType != AttributeTypeCode.Owner &&
- !lookupMD.Targets.AreEnumerablesEqualIgnoreOrder(fieldSchema.LookupType?.Split('|') ?? Array.Empty()))
- {
- return RuleResult.Failure($"LookupAttribute {fieldSchema.Name} targets {fieldSchema.LookupType} but it's expected to target: {string.Join("|", lookupMD.Targets)}");
-
- }
- return RuleResult.Success();
- }
- }
-}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/SchemaValidator.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/SchemaValidator.cs
deleted file mode 100644
index db7b482..0000000
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/SchemaValidator.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
-
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators
-{
- public class SchemaValidator : IValidator
- {
- private readonly IValidator entitySchemaValidator;
-
- public SchemaValidator(IValidator entitySchemaValidator)
- {
-
- this.entitySchemaValidator = entitySchemaValidator;
- }
-
- public async Task Validate(ImportSchema value)
- {
- var failures = new List();
- foreach (var entitySchema in value.Entity)
- {
-
- var validationResult = await entitySchemaValidator.Validate(entitySchema);
- failures.AddRange(validationResult.Failures);
-
- }
-
- return new ValidationResult
- {
- Failures = failures
- };
-
-
- }
- }
-}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ValueConverters/DataverseValueConverter.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ValueConverters/DataverseValueConverter.cs
index 97389aa..a5405e4 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ValueConverters/DataverseValueConverter.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ValueConverters/DataverseValueConverter.cs
@@ -1,4 +1,4 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ValueConverters/IDataverseValueConverter.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ValueConverters/IDataverseValueConverter.cs
index caa945b..cda9ebe 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ValueConverters/IDataverseValueConverter.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/ValueConverters/IDataverseValueConverter.cs
@@ -1,4 +1,4 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Microsoft.Xrm.Sdk.Metadata;
namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.ValueConverters
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Model/ImportSchema.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Domain/DataSchema.cs
similarity index 98%
rename from src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Model/ImportSchema.cs
rename to src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Domain/DataSchema.cs
index cd2fe28..67e0226 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Model/ImportSchema.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Domain/DataSchema.cs
@@ -1,6 +1,6 @@
using System.Xml.Serialization;
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
// using System.Xml.Serialization;
// XmlSerializer serializer = new XmlSerializer(typeof(Entities));
@@ -101,7 +101,7 @@ public class EntitySchema
}
[XmlRoot(ElementName = "entities")]
-public class ImportSchema
+public class DataSchema
{
[XmlElement(ElementName = "entity")]
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Model/EntityImport.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Domain/EntityImport.cs
similarity index 99%
rename from src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Model/EntityImport.cs
rename to src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Domain/EntityImport.cs
index 06fb2a0..2d43a2b 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Model/EntityImport.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Domain/EntityImport.cs
@@ -1,6 +1,6 @@
using System.Xml.Serialization;
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
// using System.Xml.Serialization;
// XmlSerializer serializer = new XmlSerializer(typeof(Entities));
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/IFileDataService.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/IFileDataService.cs
new file mode 100644
index 0000000..46daf83
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/IFileDataService.cs
@@ -0,0 +1,7 @@
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+
+public interface IFileDataService
+{
+ Task ReadAsync(string path);
+ Task WriteAsync(T obj, string path);
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/TaskResult.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/TaskResult.cs
new file mode 100644
index 0000000..0a7c37b
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/TaskResult.cs
@@ -0,0 +1,7 @@
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+public enum TaskResult
+{
+ Completed,
+ Failed,
+ Requeue
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/EntitySchemaValidator.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/EntitySchemaValidator.cs
similarity index 90%
rename from src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/EntitySchemaValidator.cs
rename to src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/EntitySchemaValidator.cs
index 20c8933..46c1273 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/EntitySchemaValidator.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/EntitySchemaValidator.cs
@@ -1,10 +1,11 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.RelationshipSchemas;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.RelationshipSchemas;
using Microsoft.Xrm.Sdk.Metadata;
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas
{
public class EntitySchemaValidator : IValidator
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRule.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRule.cs
similarity index 91%
rename from src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRule.cs
rename to src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRule.cs
index b401cc7..422dda0 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRule.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/FieldTypeMustMatchWithAttributeValidationRule.cs
@@ -1,9 +1,8 @@
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Mappers;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Microsoft.Xrm.Sdk.Metadata;
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.FieldSchemas;
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
public class FieldTypeMustMatchWithAttributeValidationRule : IFieldSchemaValidationRule
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/IFieldSchemaValidationRule.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/IFieldSchemaValidationRule.cs
new file mode 100644
index 0000000..4451773
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/IFieldSchemaValidationRule.cs
@@ -0,0 +1,9 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Xrm.Sdk.Metadata;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
+
+public interface IFieldSchemaValidationRule
+{
+ Task Validate(FieldSchema fieldSchema, AttributeMetadata attributeMetadata);
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRule.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRule.cs
new file mode 100644
index 0000000..c725721
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/FieldSchemas/LookupFieldsTargetsMustMatchValidationRule.cs
@@ -0,0 +1,20 @@
+using Dataverse.ConfigurationMigrationTool.Console.Common;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Xrm.Sdk.Metadata;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.FieldSchemas;
+
+public class LookupFieldsTargetsMustMatchValidationRule : IFieldSchemaValidationRule
+{
+ public async Task Validate(FieldSchema fieldSchema, AttributeMetadata attributeMetadata)
+ {
+ if (attributeMetadata is LookupAttributeMetadata lookupMD &&
+ lookupMD.AttributeType != AttributeTypeCode.Owner &&
+ !lookupMD.Targets.AreEnumerablesEqualIgnoreOrder(fieldSchema.LookupType?.Split('|') ?? Array.Empty()))
+ {
+ return RuleResult.Failure($"LookupAttribute {fieldSchema.Name} targets {fieldSchema.LookupType} but it's expected to target: {string.Join("|", lookupMD.Targets)}");
+
+ }
+ return RuleResult.Success();
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/IRelationshipSchemaValidationRule.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/IRelationshipSchemaValidationRule.cs
similarity index 59%
rename from src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/IRelationshipSchemaValidationRule.cs
rename to src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/IRelationshipSchemaValidationRule.cs
index dddc3df..44eb082 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/IRelationshipSchemaValidationRule.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/IRelationshipSchemaValidationRule.cs
@@ -1,7 +1,8 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules;
using Microsoft.Xrm.Sdk.Metadata;
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.RelationshipSchemas
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.RelationshipSchemas
{
public interface IRelationshipSchemaValidationRule
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRule.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRule.cs
similarity index 77%
rename from src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRule.cs
rename to src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRule.cs
index 2b09e40..224d611 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRule.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/SourceEntityNameMustMatchValidationRule.cs
@@ -1,7 +1,8 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules;
using Microsoft.Xrm.Sdk.Metadata;
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.RelationshipSchemas
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.RelationshipSchemas
{
public class SourceEntityNameMustMatchValidationRule : IRelationshipSchemaValidationRule
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRule.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRule.cs
similarity index 77%
rename from src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRule.cs
rename to src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRule.cs
index a1baaec..833ddb1 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRule.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/EntitySchemas/RelationshipSchemas/TargetEntityNameMustMatchValidationRule.cs
@@ -1,7 +1,8 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules;
using Microsoft.Xrm.Sdk.Metadata;
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules.EntitySchemas.RelationshipSchemas
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules.EntitySchemas.RelationshipSchemas
{
public class TargetEntityNameMustMatchValidationRule : IRelationshipSchemaValidationRule
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/RuleResult.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/RuleResult.cs
similarity index 94%
rename from src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/RuleResult.cs
rename to src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/RuleResult.cs
index d50abbc..2d49234 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Validators/Rules/RuleResult.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/Rules/RuleResult.cs
@@ -1,4 +1,4 @@
-namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Validators.Rules
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators.Rules
{
public class RuleResult
{
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/SchemaValidator.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/SchemaValidator.cs
new file mode 100644
index 0000000..f694f75
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Shared/Validators/SchemaValidator.cs
@@ -0,0 +1,33 @@
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Validators;
+
+public class SchemaValidator : IValidator
+{
+ private readonly IValidator entitySchemaValidator;
+
+ public SchemaValidator(IValidator entitySchemaValidator)
+ {
+
+ this.entitySchemaValidator = entitySchemaValidator;
+ }
+
+ public async Task Validate(DataSchema value)
+ {
+ var failures = new List();
+ foreach (var entitySchema in value.Entity)
+ {
+
+ var validationResult = await entitySchemaValidator.Validate(entitySchema);
+ failures.AddRange(validationResult.Failures);
+
+ }
+
+ return new ValidationResult
+ {
+ Failures = failures
+ };
+
+
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Program.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Program.cs
index 1fcebc1..8518e13 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Program.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Program.cs
@@ -1,4 +1,6 @@
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import;
+using Dataverse.ConfigurationMigrationTool.Console.Features;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Export;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Import;
using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
using Dataverse.ConfigurationMigrationTool.Console.Services.Dataverse;
using Dataverse.ConfigurationMigrationTool.Console.Services.Dataverse.Configuration;
@@ -40,21 +42,21 @@
services
.AddLogging(lb => lb.AddConsole())
-
+ .AddScoped()
.Configure(context.Configuration.GetSection("Dataverse"))
.Configure(context.Configuration.GetSection("Dataverse"))
.AddTransient()
- .AddSingleton()
+ .AddSingleton()
.AddTransient()
.AddTransient((sp) => (ServiceClient)sp.GetRequiredService().Create())
.AddSingleton()
.AddDataverseClient()
+ .AddConfigurationMigrationTool(context.Configuration)
.UseCommands(args)
.AddMemoryCache()
.AddTransient()
.AddTransient()
- .AddTransient()
- .AddImportFeature(context.Configuration);
+ .AddTransient();
// Configure other services.
});
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Properties/launchSettings.json b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Properties/launchSettings.json
index 6d13587..aef2781 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Properties/launchSettings.json
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Properties/launchSettings.json
@@ -6,6 +6,13 @@
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
+ },
+ "export-data": {
+ "commandName": "Project",
+ "commandLineArgs": "export-data --schema ../../../TestAssets/data_schema.xml --output ../../../TestAssets/exporteddata.xml",
+ "environmentVariables": {
+ "DOTNET_ENVIRONMENT": "Development"
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Dataverse/DataverseDomainService.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Dataverse/DataverseDomainService.cs
new file mode 100644
index 0000000..4be8b19
--- /dev/null
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Dataverse/DataverseDomainService.cs
@@ -0,0 +1,67 @@
+using Dataverse.ConfigurationMigrationTool.Console.Common;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Export;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Export.Mappers;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
+using Microsoft.Extensions.Logging;
+using Microsoft.PowerPlatform.Dataverse.Client;
+using Microsoft.Xrm.Sdk;
+using Microsoft.Xrm.Sdk.Metadata;
+using Microsoft.Xrm.Sdk.Query;
+
+namespace Dataverse.ConfigurationMigrationTool.Console.Services.Dataverse;
+public class DataverseDomainService : IDomainService
+{
+ private readonly IOrganizationServiceAsync2 _orgService;
+ private readonly ILogger _logger;
+ private static readonly IMapper<(EntitySchema, Entity), Record> _recordMapper = new DataverseRecordToRecordMapper();
+ public DataverseDomainService(IOrganizationServiceAsync2 orgService, ILogger logger)
+ {
+ _orgService = orgService;
+ _logger = logger;
+ }
+
+ public async Task> GetRecords(EntitySchema Schema)
+ {
+ var exportfields = Schema.Fields.Field.Select(f => f.Name).ToList();
+ if (exportfields.Count == 0)
+ {
+ _logger.LogWarning("No fields specified for export in schema for entity {entityName}", Schema.Name);
+ return Enumerable.Empty();
+ }
+ var query = new QueryExpression(Schema.Name)
+ {
+ ColumnSet = new ColumnSet(exportfields.ToArray()),
+
+ };
+ var entityCollection = await _orgService.RetrieveAll(query, page: 5000, _logger);
+
+ var data = entityCollection.Entities.Select(e => _recordMapper.Map((Schema, e))).ToList();
+ return data;
+ }
+
+ public async Task> GetM2mRelationships(ManyToManyRelationshipMetadata metadata)
+ {
+ var query = new QueryExpression(metadata.IntersectEntityName)
+ {
+ ColumnSet = new ColumnSet(true)
+ };
+ var entityCollection = await _orgService.RetrieveAll(query, page: 5000, _logger);
+
+ return entityCollection.Entities.GroupBy(e => e.GetAttributeValue(metadata.Entity1IntersectAttribute)).Select(g =>
+ {
+ return new M2mrelationship
+ {
+ Sourceid = g.Key,
+ Targetentityname = metadata.Entity2LogicalName,
+ Targetentitynameidfield = metadata.Entity2IntersectAttribute,
+ M2mrelationshipname = metadata.IntersectEntityName,
+ Targetids = new Targetids
+ {
+ Targetid = g.Select(e => e.GetAttributeValue(metadata.Entity2IntersectAttribute)).ToList()
+ }
+ };
+
+ }).ToList();
+ }
+}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/FileReaderDataImportProvider.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/FileReaderDataImportProvider.cs
index 4fe27e2..6290d7c 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/FileReaderDataImportProvider.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/FileReaderDataImportProvider.cs
@@ -1,33 +1,33 @@
using Dataverse.ConfigurationMigrationTool.Console.Features.Import;
-using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared.Domain;
using Microsoft.Extensions.Logging;
-namespace Dataverse.ConfigurationMigrationTool.Console.Services.Filesystem
-{
- public class FileReaderDataImportProvider : IImportDataProvider
- {
- private readonly IFileDataReader _dataReader;
- private readonly ILogger _logger;
+namespace Dataverse.ConfigurationMigrationTool.Console.Services.Filesystem;
- public FileReaderDataImportProvider(IFileDataReader dataReader,
- ILogger logger)
- {
- _dataReader = dataReader;
- _logger = logger;
- }
+public class FileReaderDataImportProvider : IImportDataProvider
+{
+ private readonly IFileDataService _dataReader;
+ private readonly ILogger _logger;
- public async Task ReadFromFile(string filePath)
- {
- _logger.LogInformation("Loading import data from {path}", filePath);
- return await _dataReader.ReadAsync(filePath);
- }
+ public FileReaderDataImportProvider(IFileDataService dataReader,
+ ILogger logger)
+ {
+ _dataReader = dataReader;
+ _logger = logger;
+ }
+ public async Task ReadFromFile(string filePath)
+ {
+ _logger.LogInformation("Loading import data from {path}", filePath);
+ return await _dataReader.ReadAsync(filePath);
+ }
- public async Task ReadSchemaFromFile(string filePath)
- {
- _logger.LogInformation("Loading schema from {path}", filePath);
- return await _dataReader.ReadAsync(filePath);
- }
+ public async Task ReadSchemaFromFile(string filePath)
+ {
+ _logger.LogInformation("Loading schema from {path}", filePath);
+ return await _dataReader.ReadAsync(filePath);
}
+
}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/IFileDataReader.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/IFileDataReader.cs
deleted file mode 100644
index a79de55..0000000
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/IFileDataReader.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Dataverse.ConfigurationMigrationTool.Console.Services.Filesystem
-{
- public interface IFileDataReader
- {
- Task ReadAsync(string path);
- }
-}
diff --git a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/XmlFileDataReader.cs b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/XmlFileDataReader.cs
index 0a423df..0569310 100644
--- a/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/XmlFileDataReader.cs
+++ b/src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Filesystem/XmlFileDataReader.cs
@@ -1,19 +1,27 @@
-using System.Text;
+using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
+using System.Text;
using System.Xml.Serialization;
-namespace Dataverse.ConfigurationMigrationTool.Console.Services.Filesystem
+namespace Dataverse.ConfigurationMigrationTool.Console.Services.Filesystem;
+
+public class XmlFileDataReader : IFileDataService
{
- public class XmlFileDataReader : IFileDataReader
+ public async Task ReadAsync(string path)
{
- public async Task ReadAsync(string path)
+ var xml = await File.ReadAllTextAsync(path, Encoding.UTF8);
+ XmlSerializer serializer = new XmlSerializer(typeof(T));
+ using (StringReader reader = new StringReader(xml))
{
- var xml = await File.ReadAllTextAsync(path, Encoding.UTF8);
- XmlSerializer serializer = new XmlSerializer(typeof(T));
- using (StringReader reader = new StringReader(xml))
- {
- var data = (T)serializer.Deserialize(reader);
- return data;
- }
+ var data = (T)serializer.Deserialize(reader);
+ return data;
}
}
+
+ public Task WriteAsync(T obj, string path)
+ {
+ var x = new XmlSerializer(typeof(T));
+ using var writer = new StreamWriter(path);
+ x.Serialize(writer, obj);
+ return Task.CompletedTask;
+ }
}