diff --git a/e2e/Sandbox/Factories/CustomDashboard.cs b/e2e/Sandbox/Factories/CustomDashboard.cs index 074b96d..7cb31e7 100644 --- a/e2e/Sandbox/Factories/CustomDashboard.cs +++ b/e2e/Sandbox/Factories/CustomDashboard.cs @@ -12,39 +12,73 @@ internal static RdashDocument CreateDashboard() { var factory = new DataSourceItemFactory(); - var excelDataSourceItem = factory.Create(DataSourceType.REST, "Marketing Sheet") - .Subtitle("Excel Data Source Item") - .Fields(DataSourceFactory.GetMarketingDataSourceFields()) - .As() - .Uri("http://dl.infragistics.com/reportplus/reveal/samples/Samples.xlsx") - .IsAnonymous(true) - .UseExcel("Marketing") - .Build(); - - var csvDataSourceItem = factory.Create(DataSourceType.REST, "Illinois School Info") - .Subtitle("CSV Data Source Item") - .Fields(DataSourceFactory.GetCsvDataSourceFields()) - .As() - .Uri("https://query.data.world/s/y32gtgblzpemyyvtig47dz7tedgkto") - .IsAnonymous(true) - .UseCsv() - .Build(); - - var financialDataSourceItem = factory.Create(DataSourceType.REST, "OHLC") - .Subtitle("Financial Data Source Item") - .Fields(DataSourceFactory.GetOHLCDataSourceFields()) - .As() - .Uri("https://excel2json.io/api/share/8bb2cd78-1b87-4142-00a2-08da188ec9ab") - .IsAnonymous(true) - .Build(); - - var revenueDataSourceItem = factory.Create(DataSourceType.REST, "Revenue") - .Subtitle("Choropleth Data Source Item") - .Fields(DataSourceFactory.GetRevenueDataSourceFields()) - .As() - .Uri("https://excel2json.io/api/share/818e7b9a-f463-4565-435d-08da496bf5f2") - .IsAnonymous(true) - .Build(); + //var excelDataSourceItem = factory.Create(DataSourceType.REST, "Marketing Sheet") + // .SetSubtitle("Excel Data Source Item") + // .SetFields(DataSourceFactory.GetMarketingDataSourceFields()) + // .As() + // .Uri("http://dl.infragistics.com/reportplus/reveal/samples/Samples.xlsx") + // .IsAnonymous(true) + // .UseExcel("Marketing") + // .Build(); + + var excelDataSourceItem = new RestDataSourceItem("Marketing Sheet") + { + Subtitle = "Excel Data Source Item", + Uri = "http://dl.infragistics.com/reportplus/reveal/samples/Samples.xlsx", + IsAnonymous = true, + Fields = DataSourceFactory.GetMarketingDataSourceFields(), + }; + excelDataSourceItem.UseExcel("Marketing"); + + //var csvDataSourceItem = factory.Create(DataSourceType.REST, "Illinois School Info") + // .SetSubtitle("CSV Data Source Item") + // .SetFields(DataSourceFactory.GetCsvDataSourceFields()) + // .As() + // .Uri("https://query.data.world/s/y32gtgblzpemyyvtig47dz7tedgkto") + // .IsAnonymous(true) + // .UseCsv() + // .Build(); + + var csvDataSourceItem = new RestDataSourceItem("Illinois School Info") + { + Subtitle = "CSV Data Source Item", + Uri = "https://query.data.world/s/y32gtgblzpemyyvtig47dz7tedgkto", + IsAnonymous = true, + Fields = DataSourceFactory.GetCsvDataSourceFields(), + }; + csvDataSourceItem.UseCsv(); + + //var financialDataSourceItem = factory.Create(DataSourceType.REST, "OHLC") + // .SetSubtitle("Financial Data Source Item") + // .SetFields(DataSourceFactory.GetOHLCDataSourceFields()) + // .As() + // .Uri("https://excel2json.io/api/share/8bb2cd78-1b87-4142-00a2-08da188ec9ab") + // .IsAnonymous(true) + // .Build(); + + var financialDataSourceItem = new RestDataSourceItem("OHLC") + { + Subtitle = "Financial Data Source Item", + Uri = "https://excel2json.io/api/share/8bb2cd78-1b87-4142-00a2-08da188ec9ab", + IsAnonymous = true, + Fields = DataSourceFactory.GetOHLCDataSourceFields(), + }; + + //var revenueDataSourceItem = factory.Create(DataSourceType.REST, "Revenue") + // .SetSubtitle("Choropleth Data Source Item") + // .SetFields(DataSourceFactory.GetRevenueDataSourceFields()) + // .As() + // .Uri("https://excel2json.io/api/share/818e7b9a-f463-4565-435d-08da496bf5f2") + // .IsAnonymous(true) + // .Build(); + + var revenueDataSourceItem = new RestDataSourceItem("Revenue") + { + Subtitle = "Choropleth Data Source Item", + Uri = "https://excel2json.io/api/share/818e7b9a-f463-4565-435d-08da496bf5f2", + IsAnonymous = true, + Fields = DataSourceFactory.GetRevenueDataSourceFields(), + }; var document = new RdashDocument() { diff --git a/e2e/Sandbox/Factories/RestDataSourceDashboards.cs b/e2e/Sandbox/Factories/RestDataSourceDashboards.cs index ffad529..032b9bf 100644 --- a/e2e/Sandbox/Factories/RestDataSourceDashboards.cs +++ b/e2e/Sandbox/Factories/RestDataSourceDashboards.cs @@ -7,61 +7,45 @@ namespace Sandbox.Factories { internal class RestDataSourceDashboards { - static IDataSourceItemFactory _factory = new DataSourceItemFactory(); - internal static RdashDocument CreateDashboard() { var document = new RdashDocument("My Dashboard"); //json - default - var jsonDataSourceItem = _factory.Create(DataSourceType.REST, "Sales by Category") - .Subtitle("JSON Data Source Item") - .Fields(DataSourceFactory.GetSalesByCategoryFields()) - .As() - .Uri("https://excel2json.io/api/share/6e0f06b3-72d3-4fec-7984-08da43f56bb9") - .IsAnonymous(true) - .ConfigureDataSource(d => - { - d.Title = "JSON DS"; - d.Subtitle = "JSON DS Subtitle"; - }) - .Build(); + var jsonDataSourceItem = new RestDataSourceItem(new DataSource { Title = "JSON DS", Subtitle = "JSON DS Subtitle" },"Sales by Category") + { + Id = "TESTING", + Subtitle = "JSON Data Source Item", + Uri = "https://excel2json.io/api/share/6e0f06b3-72d3-4fec-7984-08da43f56bb9", + IsAnonymous = true, + Fields = DataSourceFactory.GetSalesByCategoryFields(), + }; document.Visualizations.Add(new PieChartVisualization("JSON", jsonDataSourceItem) .SetLabel("CategoryName").SetValue("ProductSales")); //excel - var excelDataSourceItem = _factory.Create(DataSourceType.REST, "Marketing") - .Subtitle("Excel Data Source Item") - .Fields(DataSourceFactory.GetMarketingDataSourceFields()) - .As() - .Uri("http://dl.infragistics.com/reportplus/reveal/samples/Samples.xlsx") - .IsAnonymous(true) - .UseExcel("Marketing") - .ConfigureDataSource(d => - { - d.Title = "Excel DS"; - d.Subtitle = "Excel DS Subtitle"; - }) - .Build(); + var excelDataSourceItem = new RestDataSourceItem(new DataSource { Title = "Excel DS", Subtitle = "Excel DS Subtitle" }, "Marketing") + { + Subtitle = "Excel Data Source Item", + Uri = "http://dl.infragistics.com/reportplus/reveal/samples/Samples.xlsx", + IsAnonymous = true, + Fields = DataSourceFactory.GetMarketingDataSourceFields(), + }; + excelDataSourceItem.UseExcel("Marketing"); document.Visualizations.Add(new PieChartVisualization("Excel", excelDataSourceItem) .SetLabel("Territory").SetValue("Conversions")); //csv - var csvDataSourceItem = _factory.Create(DataSourceType.REST, "Illinois School Info") - .Subtitle("CSV Data Source Item") - .Fields(DataSourceFactory.GetCsvDataSourceFields()) - .As() - .Uri("https://query.data.world/s/y32gtgblzpemyyvtig47dz7tedgkto") - .IsAnonymous(true) - .UseCsv() - .ConfigureDataSource(d => - { - d.Title = "CSV DS"; - d.Subtitle = "CSV DS Subtitle"; - }) - .Build(); + var csvDataSourceItem = new RestDataSourceItem(new DataSource { Title = "CSV DS", Subtitle = "CSV DS Subtitle" }, "Illinois School Info") + { + Subtitle = "CSV Data Source Item", + Uri = "https://query.data.world/s/y32gtgblzpemyyvtig47dz7tedgkto", + IsAnonymous = true, + Fields = DataSourceFactory.GetCsvDataSourceFields(), + }; + csvDataSourceItem.UseCsv(); document.Visualizations.Add(new ScatterMapVisualization("Scatter", csvDataSourceItem) .SetMap(Maps.NorthAmerica.UnitedStates.States.Illinois) diff --git a/e2e/Sandbox/Factories/SqlServerDataSourceDashboards.cs b/e2e/Sandbox/Factories/SqlServerDataSourceDashboards.cs index ed16ed5..8afda3a 100644 --- a/e2e/Sandbox/Factories/SqlServerDataSourceDashboards.cs +++ b/e2e/Sandbox/Factories/SqlServerDataSourceDashboards.cs @@ -11,19 +11,19 @@ internal static RdashDocument CreateDashboard() { var document = new RdashDocument("My Dashboard"); - var sqlServerDataSourceItem = new DataSourceItemFactory().Create(DataSourceType.MicrosoftSqlServer, "Customers") - .Subtitle("SQL Server Data Source Item") - .Fields(new List + var sqlServerDataSourceItem = new MicrosoftSqlServerDataSourceItem("Customers") + { + Subtitle = "SQL Server Data Source Item", + Host = @"Brian-Desktop\SQLEXPRESS", + Database = "Northwind", + Table = "Customers", + Fields = new List { new TextField("ContactName"), new TextField("ContactTitle"), new TextField("City") - }) - .As() - .Host(@"Brian-Desktop\SQLEXPRESS") - .Database("Northwind") - .Table("Customers") - .Build(); + } + }; document.Visualizations.Add(new GridVisualization("Customer List", sqlServerDataSourceItem).SetColumns("ContactName", "ContactTitle", "City")); diff --git a/e2e/Sandbox/Helpers/DataSourceFactory.cs b/e2e/Sandbox/Helpers/DataSourceFactory.cs index 41d30b0..a3afc97 100644 --- a/e2e/Sandbox/Helpers/DataSourceFactory.cs +++ b/e2e/Sandbox/Helpers/DataSourceFactory.cs @@ -18,61 +18,60 @@ internal class DataSourceFactory internal static DataSourceItem GetMarketingDataSourceItem() { - var excelDataSourceItem = _factory.Create(DataSourceType.REST, _excelDataSource, "Marketing") - .Subtitle("Excel Data Source Item") - .Fields(GetMarketingDataSourceFields()) - .As() - .Uri(_restExcelUri) - .IsAnonymous(true) - .UseExcel("Marketing") - .Build(); + var excelDataSourceItem = new RestDataSourceItem(_excelDataSource, "Marketing") + { + Subtitle = "Excel Data Source Item", + Uri = _restExcelUri, + IsAnonymous = true, + Fields = GetMarketingDataSourceFields(), + }; + excelDataSourceItem.UseExcel("Marketing"); return excelDataSourceItem; } internal static DataSourceItem GetHealthcareDataSourceItem() { - var excelDataSourceItem = _factory.Create(DataSourceType.REST, _excelDataSource, "Healthcare") - .Subtitle("Excel Data Source Item") - .Fields(GetHealthcareDataSourceFields()) - .As() - .Uri(_restExcelUri) - .IsAnonymous(true) - .UseExcel("Healthcare") - .Build(); + var excelDataSourceItem = new RestDataSourceItem(_excelDataSource, "Healthcare") + { + Subtitle = "Excel Data Source Item", + Uri = _restExcelUri, + IsAnonymous = true, + Fields = GetHealthcareDataSourceFields(), + }; + excelDataSourceItem.UseExcel("Healthcare"); return excelDataSourceItem; } internal static DataSourceItem GetManufacturingDataSourceItem() { - var excelDataSourceItem = _factory.Create(DataSourceType.REST, _excelDataSource, "Manufacturing") - .Subtitle("Excel Data Source Item") - .Fields(GetManufacturingDataSourceFields()) - .As() - .Uri(_restExcelUri) - .IsAnonymous(true) - .UseExcel("Manufacturing") - .Build(); + var excelDataSourceItem = new RestDataSourceItem(_excelDataSource, "Manufacturing") + { + Subtitle = "Excel Data Source Item", + Uri = _restExcelUri, + IsAnonymous = true, + Fields = GetManufacturingDataSourceFields(), + }; + excelDataSourceItem.UseExcel("Manufacturing"); return excelDataSourceItem; } internal static DataSourceItem GetSalesDataSourceItem() { - var excelDataSourceItem = _factory.Create(DataSourceType.REST, _excelDataSource, "Sales") - .Subtitle("Excel Data Source Item") - .Fields(GetSalesDataSourceFields()) - .As() - .Uri(_restExcelUri) - .IsAnonymous(true) - .UseExcel("Sales") - .Build(); + var excelDataSourceItem = new RestDataSourceItem(_excelDataSource, "Sales") + { + Subtitle = "Excel Data Source Item", + Uri = _restExcelUri, + IsAnonymous = true, + Fields = GetSalesDataSourceFields(), + }; return excelDataSourceItem; } - internal static IEnumerable GetRevenueDataSourceFields() + internal static List GetRevenueDataSourceFields() { return new List() { @@ -198,7 +197,7 @@ internal static List GetCsvDataSourceFields() }; } - internal static IEnumerable GetOHLCDataSourceFields() + internal static List GetOHLCDataSourceFields() { return new List { diff --git a/e2e/Sandbox/MainWindow.xaml.cs b/e2e/Sandbox/MainWindow.xaml.cs index 43b2b94..2938f00 100644 --- a/e2e/Sandbox/MainWindow.xaml.cs +++ b/e2e/Sandbox/MainWindow.xaml.cs @@ -188,8 +188,8 @@ private async void Create_Dashboard(object sender, RoutedEventArgs e) //var document = CampaignsDashboard.CreateDashboard(); //var document = HealthcareDashboard.CreateDashboard(); //var document = ManufacturingDashboard.CreateDashboard(); - var document = CustomDashboard.CreateDashboard(); - //var document = RestDataSourceDashboards.CreateDashboard(); + //var document = CustomDashboard.CreateDashboard(); + var document = RestDataSourceDashboards.CreateDashboard(); //var document = SqlServerDataSourceDashboards.CreateDashboard(); //var document = DashboardLinkingDashboard.CreateDashboard(); diff --git a/src/Reveal.Sdk.Dom.Tests/Core/Utilities/RdashDocumentValidatorFixture.cs b/src/Reveal.Sdk.Dom.Tests/Core/Utilities/RdashDocumentValidatorFixture.cs index e0e76ed..b5cfa58 100644 --- a/src/Reveal.Sdk.Dom.Tests/Core/Utilities/RdashDocumentValidatorFixture.cs +++ b/src/Reveal.Sdk.Dom.Tests/Core/Utilities/RdashDocumentValidatorFixture.cs @@ -12,7 +12,7 @@ public class RdashDocumentValidatorFixture [Fact] public void DataSources_AddedToRdashDocument() { - var dataSourceItem = new DataSourceItemFactory().Create(DataSourceType.REST, "").Fields(new List() { null }).Build(); + var dataSourceItem = new DataSourceItemFactory().Create(DataSourceType.REST, "").SetFields(new List() { null }); var document = new RdashDocument(); document.Visualizations.Add(new KpiTimeVisualization(dataSourceItem)); @@ -27,7 +27,7 @@ public void DataSources_AddedToRdashDocument() [Fact] public void DataSources_FromVisualizationsAreNotDuplicated() { - var dataSourceItem = new DataSourceItemFactory().Create(DataSourceType.REST, "").Fields(new List() { null }).Build(); + var dataSourceItem = new DataSourceItemFactory().Create(DataSourceType.REST, "").SetFields(new List() { null }); var document = new RdashDocument(); document.Visualizations.Add(new KpiTimeVisualization(dataSourceItem)); @@ -47,7 +47,7 @@ public void DataSources_FromVisualizationsAreNotDuplicated() [Fact] public void DataSources_FromVisualizations_AndDataSources_AreNotDuplicated() { - var dataSourceItem = new DataSourceItemFactory().Create(DataSourceType.REST, "").Fields(new List() { null }).Build(); + var dataSourceItem = new DataSourceItemFactory().Create(DataSourceType.REST, "").SetFields(new List() { null }); var dataSource = dataSourceItem.DataSource; var document = new RdashDocument(); diff --git a/src/Reveal.Sdk.Dom.Tests/Data/RestDataSourceItemFixture.cs b/src/Reveal.Sdk.Dom.Tests/Data/RestDataSourceItemFixture.cs new file mode 100644 index 0000000..e846c89 --- /dev/null +++ b/src/Reveal.Sdk.Dom.Tests/Data/RestDataSourceItemFixture.cs @@ -0,0 +1,315 @@ +using Reveal.Sdk.Dom.Core.Constants; +using Reveal.Sdk.Dom.Core.Extensions; +using Reveal.Sdk.Dom.Data; +using Reveal.Sdk.Dom.Visualizations; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace Reveal.Sdk.Dom.Tests.Data +{ + public class RestDataSourceItemFixture + { + [Fact] + public void IsAnonymous_Should_Set_IsAnonymous_Property() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + + // Act + restDataSourceItem.IsAnonymous = true; + + // Assert + Assert.True(restDataSourceItem.IsAnonymous); + } + + [Fact] + public void HasTabularData_Should_Be_True() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + + // Assert + Assert.True(restDataSourceItem.HasTabularData); + } + + [Fact] + public void HasAsset_Should_Be_False() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + + // Assert + Assert.False(restDataSourceItem.HasAsset); + } + + [Fact] + public void Id_Should_Set_Id_And_ResourceItem_Id_Property() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + var id = "Test Id"; + + // Act + restDataSourceItem.Id = id; + + // Assert + Assert.Equal(id, restDataSourceItem.Id); + Assert.Equal(id, restDataSourceItem.ResourceItem.Id); + } + + [Fact] + public void Title_Should_Set_Title_Property() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + var title = "Test Title"; + + // Act + restDataSourceItem.Title = title; + + // Assert + Assert.Equal(title, restDataSourceItem.Title); + } + + [Fact] + public void Subtitle_Should_Set_Subtitle_And_ResourceItem_Subtitle_Property() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + var subtitle = "Test Subtitle"; + + // Act + restDataSourceItem.Subtitle = subtitle; + + // Assert + Assert.Equal(subtitle, restDataSourceItem.Subtitle); + Assert.Equal(subtitle, restDataSourceItem.ResourceItem.Subtitle); + } + + [Fact] + public void Uri_Should_Set_Uri_Property() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + var uri = "https://example.com/api/data"; + + // Act + restDataSourceItem.Uri = uri; + + // Assert + Assert.Equal(uri, restDataSourceItem.Uri); + } + + [Fact] + public void UseCsv_Should_Set_Id_And_Provider_And_ResultType_Properties() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + + // Act + restDataSourceItem.UseCsv(); + + // Assert + Assert.Equal(DataSourceIds.CSV, restDataSourceItem.DataSource.Id); + Assert.Equal(DataSourceIds.CSV, restDataSourceItem.DataSourceId); + Assert.Equal(DataSourceProvider.CSV, restDataSourceItem.DataSource.Provider); + Assert.Equal(".csv", restDataSourceItem.ResourceItemDataSource.Properties.GetValue("Result-Type")); + } + + [Fact] + public void UseCsv_Clears_Config() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test") + { + Fields = new List + { + new NumberField { FieldName = "Field1" }, + new DateField { FieldName = "Field2" }, + new DateTimeField { FieldName = "Field3" }, + new TimeField { FieldName = "Field4" }, + new TextField { FieldName = "Field5" } + } + }; + + // Act + restDataSourceItem.UseCsv(); + + // Assert + Assert.False(restDataSourceItem.Parameters.ContainsKey("config")); + } + + [Fact] + public void UseExcel_Should_Set_Id_And_Provider_And_ResultType_Properties() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + var sheet = "Sheet1"; + var fileType = ExcelFileType.Xlsx; + + // Act + restDataSourceItem.UseExcel(sheet, fileType); + + // Assert + Assert.Equal(DataSourceIds.Excel, restDataSourceItem.DataSource.Id); + Assert.Equal(DataSourceIds.Excel, restDataSourceItem.DataSourceId); + Assert.Equal(DataSourceProvider.MicrosoftExcel, restDataSourceItem.DataSource.Provider); + Assert.Equal(fileType == ExcelFileType.Xlsx ? ".xlsx" : ".xls", restDataSourceItem.ResourceItemDataSource.Properties.GetValue("Result-Type")); + Assert.Equal(sheet, restDataSourceItem.Properties.GetValue("Sheet")); + } + + [Fact] + public void UseExcel_Clears_Config() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test") + { + Fields = new List + { + new NumberField { FieldName = "Field1" }, + new DateField { FieldName = "Field2" }, + new DateTimeField { FieldName = "Field3" }, + new TimeField { FieldName = "Field4" }, + new TextField { FieldName = "Field5" } + } + }; + + // Act + restDataSourceItem.UseExcel(); + + // Assert + Assert.False(restDataSourceItem.Parameters.ContainsKey("config")); + } + + [Fact] + public void InitializeDataSource_Should_Set_Provider_And_DataSourceId_Properties() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + + // Assert + Assert.Equal(DataSourceProvider.JSON, restDataSourceItem.DataSource.Provider); + Assert.Equal(DataSourceIds.JSON, restDataSourceItem.DataSource.Id); + } + + [Fact] + public void FieldsPropertyChanged_Should_Add_Config_Parameter() + { + // Arrange + var restDataSourceItem = new RestDataSourceItem("Test"); + var fields = new List + { + new NumberField { FieldName = "Field1" }, + new DateField { FieldName = "Field2" }, + new DateTimeField { FieldName = "Field3" }, + new TimeField { FieldName = "Field4" }, + new TextField { FieldName = "Field5" } + }; + + // Act + restDataSourceItem.Fields = fields; + + // Assert + Assert.True(restDataSourceItem.Parameters.ContainsKey("config")); + var config = restDataSourceItem.Parameters["config"] as Dictionary; + Assert.NotNull(config); + Assert.Equal(0, config["iterationDepth"]); + var columnConfigs = config["columnsConfig"] as List; + Assert.NotNull(columnConfigs); + Assert.Equal(5, columnConfigs.Count); + Assert.Equal("Field1", columnConfigs[0].Key); + Assert.Equal(1, columnConfigs[0].Type); + Assert.Equal("Field2", columnConfigs[1].Key); + Assert.Equal(2, columnConfigs[1].Type); + Assert.Equal("Field3", columnConfigs[2].Key); + Assert.Equal(3, columnConfigs[2].Type); + Assert.Equal("Field4", columnConfigs[3].Key); + Assert.Equal(4, columnConfigs[3].Type); + } + + [Fact] + public void AddHeader_Should_AddHeaderToList_When_PropertyKeyDoesNotExist() + { + // Arrange + var dataSourceItem = new RestDataSourceItem("Test"); + var headerType = HeaderType.Authorization; + var value = "Bearer token"; + + // Act + dataSourceItem.AddHeader(headerType, value); + + // Assert + Assert.Single((IEnumerable)dataSourceItem.ResourceItemDataSource.Properties["Headers"]); + Assert.Equal("Authorization=Bearer token", ((IEnumerable)dataSourceItem.ResourceItemDataSource.Properties["Headers"]).Cast().First()); + } + + [Fact] + public void AddHeader_Should_AddHeaderToList_When_PropertyKeyExists() + { + // Arrange + var dataSourceItem = new RestDataSourceItem("Test"); + var headerType = HeaderType.Authorization; + var value1 = "Bearer token1"; + var value2 = "Bearer token2"; + + // Act + dataSourceItem.AddHeader(headerType, value1); + dataSourceItem.AddHeader(headerType, value2); + + // Assert + var headers = dataSourceItem.ResourceItemDataSource.Properties["Headers"] as List; + Assert.NotNull(headers); + Assert.Equal(2, headers.Count); + Assert.Equal("Authorization=Bearer token1", headers[0]); + Assert.Equal("Authorization=Bearer token2", headers[1]); + } + + [Fact] + public void AddHeader_ShouldAddHeaderWithCorrectEnumName() + { + // Arrange + var dataSourceItem = new RestDataSourceItem("Test"); + var headerType = HeaderType.UserAgent; + var value = "token"; + + // Act + dataSourceItem.AddHeader(headerType, value); + + // Assert + var headers = dataSourceItem.ResourceItemDataSource.Properties["Headers"] as List; + Assert.NotNull(headers); + Assert.Single(headers); + Assert.Equal("User-Agent=token", headers[0]); + } + + [Fact] + public void DataSource_Properties_Should_Set_ResourceItemDataSource_Properties() + { + // Arrange + var dataSource = new DataSource() { Id = "DS-ID", Title = "DS-TITLE", Subtitle = "DS-SUBTITLE" }; + var dataSourceItem = new RestDataSourceItem(dataSource, "Test"); + + // Assert + Assert.Equal(dataSource.Id, dataSourceItem.ResourceItemDataSource.Id); + Assert.Equal(dataSource.Title, dataSourceItem.ResourceItemDataSource.Title); + Assert.Equal(dataSource.Subtitle, dataSourceItem.ResourceItemDataSource.Subtitle); + Assert.NotEqual(dataSource.Id, dataSourceItem.DataSource.Id); + Assert.NotEqual(dataSource.Title, dataSourceItem.DataSource.Title); + Assert.NotEqual(dataSource.Subtitle, dataSourceItem.DataSource.Subtitle); + } + + [Fact] + public void DataSource_No_Title_Or_Subtitle_Should_Use_ResourceItem_Title_Or_Subtitle() + { + // Arrange + var dataSource = new DataSource(); + var dataSourceItem = new RestDataSourceItem(dataSource, "Test"); + + // Assert + Assert.Equal(dataSourceItem.ResourceItemDataSource.Title, dataSourceItem.ResourceItem.Title); + Assert.Equal(dataSourceItem.ResourceItemDataSource.Subtitle, dataSourceItem.ResourceItem.Subtitle); + } + } +} diff --git a/src/Reveal.Sdk.Dom.Tests/RdashDocumentFixture.cs b/src/Reveal.Sdk.Dom.Tests/RdashDocumentFixture.cs index 8f237b8..7240682 100644 --- a/src/Reveal.Sdk.Dom.Tests/RdashDocumentFixture.cs +++ b/src/Reveal.Sdk.Dom.Tests/RdashDocumentFixture.cs @@ -53,7 +53,7 @@ public void RdashDocument_TitleConstructor_ShouldSetTitle() public void RdashDocument_Import_ShouldImportVisualizations() { // Arrange - var dataSourceItem = new DataSourceItemFactory().Create(DataSourceType.REST, "").Fields(new List() { null }).Build(); + var dataSourceItem = new DataSourceItemFactory().Create(DataSourceType.REST, "").SetFields(new List() { null }); var sourceDocument = new RdashDocument(); sourceDocument.Visualizations.Add(new KpiTimeVisualization(dataSourceItem)); @@ -79,7 +79,7 @@ public void RdashDocument_Import_ShouldImportVisualizations() public void RdashDocument_Import_ShouldImportSingleVisualization() { // Arrange - var dataSourceItem = new DataSourceItemFactory().Create(DataSourceType.REST, "").Fields(new List() { null }).Build(); + var dataSourceItem = new DataSourceItemFactory().Create(DataSourceType.REST, "").SetFields(new List() { null }); var sourceDocument = new RdashDocument(); sourceDocument.Visualizations.Add(new KpiTimeVisualization(dataSourceItem)); diff --git a/src/Reveal.Sdk.Dom/Core/Extensions/DictionaryExtensions.cs b/src/Reveal.Sdk.Dom/Core/Extensions/DictionaryExtensions.cs index e840df7..7b81dd2 100644 --- a/src/Reveal.Sdk.Dom/Core/Extensions/DictionaryExtensions.cs +++ b/src/Reveal.Sdk.Dom/Core/Extensions/DictionaryExtensions.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Reveal.Sdk.Dom.Core.Extensions { @@ -11,5 +12,28 @@ public static void SetItem(this Dictionary dictionary, string ke else dictionary.Add(key, value); } + + public static T GetValue(this IDictionary dictionary, string key, T defaultValue = default) + { + if (dictionary.TryGetValue(key, out var value) && value != null) + { + if (value is T typedValue) + { + return typedValue; + } + else + { + try + { + return (T)Convert.ChangeType(value, typeof(T)); + } + catch (InvalidCastException) + { + throw new InvalidCastException($"The value associated with the key '{key}' cannot be cast to type {typeof(T).Name}."); + } + } + } + return defaultValue; + } } } diff --git a/src/Reveal.Sdk.Dom/Data/Builders/DataSourceItemBuilder.cs b/src/Reveal.Sdk.Dom/Data/Builders/DataSourceItemBuilder.cs deleted file mode 100644 index 6f83e14..0000000 --- a/src/Reveal.Sdk.Dom/Data/Builders/DataSourceItemBuilder.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Reveal.Sdk.Dom.Visualizations; -using System; -using System.Collections.Generic; - -namespace Reveal.Sdk.Dom.Data -{ - public abstract class DataSourceItemBuilder : IDataSourceItemBuilder - { - protected DataSource DataSource { get; set; } - protected DataSourceItem DataSourceItem { get; set; } - - public DataSourceItemBuilder(DataSourceProvider provider, string title) : - this(new DataSource(), provider, title) - { } - - public DataSourceItemBuilder(DataSource dataSource, DataSourceProvider provider, string title) - { - InitializeDataSource(dataSource, provider, title); - InitializeDataSourceItem(title); - } - - public virtual DataSourceItem Build() - { - //todo: need to revist to support xmla data sources - //fields is only used for tabular data sources - if (DataSourceItem.Fields.Count == 0) - throw new ArgumentException("You must provide the field definitions for the data source item. Call the SetFields method and provide the fields."); - - return DataSourceItem; - } - - public virtual IDataSourceItemBuilder Id(string id) - { - DataSourceItem.Id = id; - return this; - } - - public virtual IDataSourceItemBuilder Fields(IEnumerable fields) - { - DataSourceItem.Fields.Clear(); - DataSourceItem.Fields.AddRange(fields); - return this; - } - - public virtual IDataSourceItemBuilder Fields(params IField[] fields) - { - return Fields((IEnumerable)fields); - } - - public virtual IDataSourceItemBuilder Subtitle(string subtitle) - { - DataSourceItem.Subtitle = subtitle; - if (string.IsNullOrEmpty(DataSource.Subtitle)) - DataSource.Subtitle = subtitle; - - return this; - } - - public virtual IDataSourceItemBuilder ConfigureDataSource(Action configureDataSource) - { - configureDataSource.Invoke(DataSource); - UpdateDataSourceId(DataSource.Id); - return this; - } - - protected void UpdateDataSourceId(string id) - { - DataSource.Id = id; - DataSourceItem.DataSourceId = id; - } - - private void InitializeDataSource(DataSource dataSource, DataSourceProvider provider, string title) - { - DataSource = dataSource ?? new DataSource(); - DataSource.Provider = provider; // //todo: maybe this shouldn't go here. Each specific builder should be responsible for setting the provider - if (string.IsNullOrEmpty(DataSource.Title)) - DataSource.Title = title; - } - - private void InitializeDataSourceItem(string title) - { - DataSourceItem = new DataSourceItem - { - DataSource = DataSource, - DataSourceId = DataSource.Id, - Title = title, - }; - } - } -} diff --git a/src/Reveal.Sdk.Dom/Data/Builders/DataSourceResourceItemBuilder.cs b/src/Reveal.Sdk.Dom/Data/Builders/DataSourceResourceItemBuilder.cs deleted file mode 100644 index 765e0dd..0000000 --- a/src/Reveal.Sdk.Dom/Data/Builders/DataSourceResourceItemBuilder.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Reveal.Sdk.Dom.Data -{ - public abstract class DataSourceResourceItemBuilder : DataSourceItemBuilder - { - protected DataSource ResourceItemDataSource { get; private set; } //resource item data source - protected DataSourceItem ResourceItem { get; private set; } //resource item that points to the data source - - public DataSourceResourceItemBuilder(DataSourceProvider dataSourceProvider, DataSourceProvider resourceItemDataSourceProvider, string title) : - this(new DataSource(), dataSourceProvider, resourceItemDataSourceProvider, title) - { } - - public DataSourceResourceItemBuilder(DataSource dataSource, DataSourceProvider dataSourceProvider, DataSourceProvider resourceItemDataSourceProvider, string title) : - base(dataSource, dataSourceProvider, title) - { - InitializeResourceItem(resourceItemDataSourceProvider, title); - } - - private void InitializeResourceItem(DataSourceProvider resourceItemDataSourceProvider, string title) - { - ResourceItemDataSource = new DataSource { Provider = resourceItemDataSourceProvider }; - ResourceItem = new DataSourceItem - { - DataSource = ResourceItemDataSource, - DataSourceId = ResourceItemDataSource.Id, - Title = title - }; - - DataSourceItem.ResourceItemDataSource = ResourceItemDataSource; - DataSourceItem.ResourceItem = ResourceItem; - } - } -} diff --git a/src/Reveal.Sdk.Dom/Data/Builders/Extensions/IDataSourceBuilderExtensions.cs b/src/Reveal.Sdk.Dom/Data/Builders/Extensions/IDataSourceBuilderExtensions.cs deleted file mode 100644 index c61d8cf..0000000 --- a/src/Reveal.Sdk.Dom/Data/Builders/Extensions/IDataSourceBuilderExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Reveal.Sdk.Dom.Data -{ - public static class IDataSourceBuilderExtensions - { - public static T As(this IDataSourceItemBuilder builder) where T : class, IDataSourceItemBuilder - { - return builder as T; - } - } -} diff --git a/src/Reveal.Sdk.Dom/Data/Builders/Interfaces/IDataSourceItemBuilder.cs b/src/Reveal.Sdk.Dom/Data/Builders/Interfaces/IDataSourceItemBuilder.cs deleted file mode 100644 index 2a8dbba..0000000 --- a/src/Reveal.Sdk.Dom/Data/Builders/Interfaces/IDataSourceItemBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Reveal.Sdk.Dom.Visualizations; -using System; -using System.Collections.Generic; - -namespace Reveal.Sdk.Dom.Data -{ - public interface IDataSourceItemBuilder - { - IDataSourceItemBuilder Id(string id); - IDataSourceItemBuilder Fields(IEnumerable fields); - IDataSourceItemBuilder Fields(params IField[] fields); - IDataSourceItemBuilder Subtitle(string subtitle); - IDataSourceItemBuilder ConfigureDataSource(Action configureDataSource); - DataSourceItem Build(); - } -} diff --git a/src/Reveal.Sdk.Dom/Data/Builders/Interfaces/IRestDataSourceItemBuilder.cs b/src/Reveal.Sdk.Dom/Data/Builders/Interfaces/IRestDataSourceItemBuilder.cs deleted file mode 100644 index e8149c8..0000000 --- a/src/Reveal.Sdk.Dom/Data/Builders/Interfaces/IRestDataSourceItemBuilder.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Reveal.Sdk.Dom.Data -{ - public interface IRestDataSourceItemBuilder : IDataSourceItemBuilder - { - IRestDataSourceItemBuilder AddHeader(HeaderType headerType, string value); - IRestDataSourceItemBuilder IsAnonymous(bool isAnonymous); - IRestDataSourceItemBuilder UseCsv(); - IRestDataSourceItemBuilder UseExcel(string sheet = null, ExcelFileType fileType = ExcelFileType.Xlsx); - IRestDataSourceItemBuilder Uri(string uri); - } -} diff --git a/src/Reveal.Sdk.Dom/Data/Builders/Interfaces/ISqlDataSourceItemBuilder.cs b/src/Reveal.Sdk.Dom/Data/Builders/Interfaces/ISqlDataSourceItemBuilder.cs deleted file mode 100644 index 122ba32..0000000 --- a/src/Reveal.Sdk.Dom/Data/Builders/Interfaces/ISqlDataSourceItemBuilder.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Reveal.Sdk.Dom.Data -{ - public interface ISqlDataSourceItemBuilder : IDataSourceItemBuilder - { - ISqlDataSourceItemBuilder Database(string database); - ISqlDataSourceItemBuilder Host(string host); - ISqlDataSourceItemBuilder Schema(string schema); - ISqlDataSourceItemBuilder Table(string table); - } -} diff --git a/src/Reveal.Sdk.Dom/Data/Builders/SqlDataSourceItemBuilder.cs b/src/Reveal.Sdk.Dom/Data/Builders/SqlDataSourceItemBuilder.cs deleted file mode 100644 index a8ce4b3..0000000 --- a/src/Reveal.Sdk.Dom/Data/Builders/SqlDataSourceItemBuilder.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Reveal.Sdk.Dom.Core.Extensions; - -namespace Reveal.Sdk.Dom.Data -{ - public class SqlDataSourceItemBuilder : DataSourceItemBuilder, ISqlDataSourceItemBuilder - { - //bug: if the database is not provided, the DSI Title will not be shown in the UI - - //todo: support more sql based connectors - public SqlDataSourceItemBuilder(DataSource dataSource, string title) : - base(dataSource, DataSourceProvider.MicrosoftSqlServer, title) - { - Schema("dbo"); - DataSource.Properties.SetItem("ServerAggregationDefault", true); - DataSource.Properties.SetItem("ServerAggregationReadOnly", false); - DataSourceItem.Properties.SetItem("ServerAggregation", true); - } - - public ISqlDataSourceItemBuilder Database(string database) - { - DataSource.Properties.SetItem("Database", database); - DataSourceItem.Properties.SetItem("Database", database); - return this; - } - - public ISqlDataSourceItemBuilder Host(string host) - { - DataSource.Properties.SetItem("Host", host); - return this; - } - - public ISqlDataSourceItemBuilder Schema(string schema) - { - DataSourceItem.Properties.SetItem("Schema", schema); - return this; - } - - public ISqlDataSourceItemBuilder Table(string table) - { - DataSourceItem.Properties.SetItem("Table", table); - return this; - } - } -} diff --git a/src/Reveal.Sdk.Dom/Data/DataSourceItem.cs b/src/Reveal.Sdk.Dom/Data/DataSourceItem.cs index 90c4e66..335b0c3 100644 --- a/src/Reveal.Sdk.Dom/Data/DataSourceItem.cs +++ b/src/Reveal.Sdk.Dom/Data/DataSourceItem.cs @@ -7,32 +7,74 @@ namespace Reveal.Sdk.Dom.Data { - public sealed class DataSourceItem : SchemaType + public class DataSourceItem : SchemaType { - private string _id = Guid.NewGuid().ToString(); + public DataSourceItem(DataSource dataSource, string title) : this() + { + InitializeDataSource(dataSource, title); + InitializeDataSourceItem(title); + } public DataSourceItem() { SchemaTypeName = SchemaTypeNames.DataSourceItemType; } + private string _id = Guid.NewGuid().ToString(); public string Id { get => _id; - set => _id = string.IsNullOrEmpty(value) ? Guid.NewGuid().ToString() : value; //do not allow a null Id + set + { + _id = string.IsNullOrEmpty(value) ? Guid.NewGuid().ToString() : value; + if (ResourceItem != null) //if we are dealing with a resource item, set the id on the resource item to be the same + ResourceItem.Id = _id; + } } public string Title { get; set; } - public string Subtitle { get; set; } - public string DataSourceId { get; set; } //todo: can this be internal? - public bool HasTabularData { get; set; } = true; //todo: can this be internal? - public bool HasAsset { get; set; } //todo: can this be internal? - public Dictionary Properties { get; set; } = new Dictionary(); //todo: can this be internal? - public Dictionary Parameters { get; set; } = new Dictionary(); //todo: can this be internal? - public DataSourceItem ResourceItem { get; set; } //todo: can this be internal? + private string _subtitle; + public string Subtitle + { + get => _subtitle; + set + { + _subtitle = value; + if (ResourceItem != null) + ResourceItem.Subtitle = value; + } + } + + [JsonProperty] + internal string DataSourceId { get; set; } + + [JsonProperty] + internal bool HasTabularData { get; set; } = true; + + [JsonProperty] + internal bool HasAsset { get; set; } + + [JsonProperty] + internal Dictionary Properties { get; set; } = new Dictionary(); + + [JsonProperty] + internal Dictionary Parameters { get; set; } = new Dictionary(); + + [JsonProperty] + internal DataSourceItem ResourceItem { get; set; } + + private List _fields = new List(); [JsonIgnore] - internal List Fields { get; set; } = new List(); + public List Fields + { + get => _fields; + set + { + _fields = value; + OnFieldsPropertyChanged(_fields); + } + } /// /// The data source for the current DataSourceItem. This is set internally by a data source builder and is only used during the RdashDocumentValidator process. @@ -47,5 +89,41 @@ public string Id /// [JsonIgnore] internal DataSource ResourceItemDataSource { get; set; } + + protected virtual void InitializeDataSource(DataSource dataSource, string title) + { + DataSource = dataSource ?? new DataSource(); + if (string.IsNullOrEmpty(DataSource.Title)) + DataSource.Title = title; + + DataSourceId = DataSource.Id; + } + + protected virtual void InitializeDataSourceItem(string title) + { + Title = title; + } + + protected virtual void InitializeResourceItem(DataSourceProvider resourceItemDataSourceProvider, string title) + { + ResourceItemDataSource = new DataSource { Provider = resourceItemDataSourceProvider }; + ResourceItem = new DataSourceItem + { + DataSource = ResourceItemDataSource, + DataSourceId = ResourceItemDataSource.Id, + Title = title + }; + + ResourceItemDataSource = ResourceItemDataSource; + ResourceItem = ResourceItem; + } + + protected virtual void OnFieldsPropertyChanged(List fields) { } + + protected virtual void UpdateDataSourceId(string id) + { + DataSource.Id = id; + DataSourceId = id; + } } } diff --git a/src/Reveal.Sdk.Dom/Data/DataSourceItemFactory.cs b/src/Reveal.Sdk.Dom/Data/DataSourceItemFactory.cs index 342dc13..9f12c13 100644 --- a/src/Reveal.Sdk.Dom/Data/DataSourceItemFactory.cs +++ b/src/Reveal.Sdk.Dom/Data/DataSourceItemFactory.cs @@ -4,24 +4,24 @@ namespace Reveal.Sdk.Dom.Data { public interface IDataSourceItemFactory { - IDataSourceItemBuilder Create(DataSourceType type, string title); + DataSourceItem Create(DataSourceType type, string title); - IDataSourceItemBuilder Create(DataSourceType type, DataSource dataSource, string title); + DataSourceItem Create(DataSourceType type, DataSource dataSource, string title); } public class DataSourceItemFactory : IDataSourceItemFactory { - public IDataSourceItemBuilder Create(DataSourceType type, string title) + public DataSourceItem Create(DataSourceType type, string title) { return Create(type, new DataSource(), title); } - public IDataSourceItemBuilder Create(DataSourceType type, DataSource dataSource, string title) + public DataSourceItem Create(DataSourceType type, DataSource dataSource, string title) { return type switch { - DataSourceType.MicrosoftSqlServer => new SqlDataSourceItemBuilder(dataSource, title), - DataSourceType.REST => new RestDataSourceItemBuilder(dataSource, title), + DataSourceType.MicrosoftSqlServer => new MicrosoftSqlServerDataSourceItem(dataSource, title), + DataSourceType.REST => new RestDataSourceItem(dataSource, title), _ => throw new NotImplementedException($"No builder implemented for provider: {type}") }; } diff --git a/src/Reveal.Sdk.Dom/Data/Builders/Enums/DataSourceType.cs b/src/Reveal.Sdk.Dom/Data/Enums/DataSourceType.cs similarity index 93% rename from src/Reveal.Sdk.Dom/Data/Builders/Enums/DataSourceType.cs rename to src/Reveal.Sdk.Dom/Data/Enums/DataSourceType.cs index 92d8186..949210b 100644 --- a/src/Reveal.Sdk.Dom/Data/Builders/Enums/DataSourceType.cs +++ b/src/Reveal.Sdk.Dom/Data/Enums/DataSourceType.cs @@ -1,8 +1,8 @@ -namespace Reveal.Sdk.Dom.Data -{ - public enum DataSourceType - { - REST, - MicrosoftSqlServer - } -} +namespace Reveal.Sdk.Dom.Data +{ + public enum DataSourceType + { + REST, + MicrosoftSqlServer + } +} diff --git a/src/Reveal.Sdk.Dom/Data/Extensions/IDataSourceItemExtensions.cs b/src/Reveal.Sdk.Dom/Data/Extensions/IDataSourceItemExtensions.cs new file mode 100644 index 0000000..be3d49a --- /dev/null +++ b/src/Reveal.Sdk.Dom/Data/Extensions/IDataSourceItemExtensions.cs @@ -0,0 +1,43 @@ +using Reveal.Sdk.Dom.Visualizations; +using System.Collections.Generic; + +namespace Reveal.Sdk.Dom.Data +{ + public static class IDataSourceItemExtensions + { + public static T As(this DataSourceItem dsi) where T : DataSourceItem + { + return dsi as T; + } + + public static T SetId(this T dsi, string id) where T : DataSourceItem + { + dsi.Id = id; + return dsi; + } + + public static T SetFields(this T dsi, IEnumerable fields) where T : DataSourceItem + { + dsi.Fields.Clear(); + dsi.Fields.AddRange(fields); + return dsi; + } + + public static T SetFields(this T dsi, params IField[] fields) where T : DataSourceItem + { + return SetFields(dsi, (IEnumerable)fields); + } + + public static T SetTitle(this T dsi, string title) where T : DataSourceItem + { + dsi.Title = title; + return dsi; + } + + public static T SetSubtitle(this T dsi, string subtitle) where T : DataSourceItem + { + dsi.Subtitle = subtitle; + return dsi; + } + } +} diff --git a/src/Reveal.Sdk.Dom/Data/MicrosoftSqlServerDataSourceItem.cs b/src/Reveal.Sdk.Dom/Data/MicrosoftSqlServerDataSourceItem.cs new file mode 100644 index 0000000..aa414bb --- /dev/null +++ b/src/Reveal.Sdk.Dom/Data/MicrosoftSqlServerDataSourceItem.cs @@ -0,0 +1,58 @@ +using Reveal.Sdk.Dom.Core.Extensions; + +namespace Reveal.Sdk.Dom.Data +{ + public class MicrosoftSqlServerDataSourceItem : DataSourceItem + { + public MicrosoftSqlServerDataSourceItem(string title) : + this(new DataSource(), title) + { } + + public MicrosoftSqlServerDataSourceItem(DataSource dataSource, string title) : + base(dataSource, title) + { } + + public string Database + { + get => Properties.GetValue("Database"); + set + { + Properties.SetItem("Database", value); + DataSource.Properties.SetItem("Database", value); + } + } + + public string Host + { + get => DataSource.Properties.GetValue("Host"); + set => DataSource.Properties.SetItem("Host", value); + } + + public string Schema + { + get => Properties.GetValue("Schema"); + set => Properties.SetItem("Schema", value); + } + + public string Table + { + get => Properties.GetValue("Table"); + set => Properties.SetItem("Table", value); + } + + protected override void InitializeDataSource(DataSource dataSource, string title) + { + base.InitializeDataSource(dataSource, title); + DataSource.Provider = DataSourceProvider.MicrosoftSqlServer; + DataSource.Properties.SetItem("ServerAggregationDefault", true); + DataSource.Properties.SetItem("ServerAggregationReadOnly", false); + } + + override protected void InitializeDataSourceItem(string title) + { + base.InitializeDataSourceItem(title); + Schema = "dbo"; + Properties.SetItem("ServerAggregation", true); + } + } +} diff --git a/src/Reveal.Sdk.Dom/Data/Builders/RestDataSourceItemBuilder.cs b/src/Reveal.Sdk.Dom/Data/RestDataSourceItem.cs similarity index 56% rename from src/Reveal.Sdk.Dom/Data/Builders/RestDataSourceItemBuilder.cs rename to src/Reveal.Sdk.Dom/Data/RestDataSourceItem.cs index 5c7200d..4f7a8e3 100644 --- a/src/Reveal.Sdk.Dom/Data/Builders/RestDataSourceItemBuilder.cs +++ b/src/Reveal.Sdk.Dom/Data/RestDataSourceItem.cs @@ -1,164 +1,145 @@ -using Reveal.Sdk.Dom.Core.Constants; -using Reveal.Sdk.Dom.Core.Extensions; -using Reveal.Sdk.Dom.Visualizations; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Reveal.Sdk.Dom.Data -{ - public class RestDataSourceItemBuilder : DataSourceResourceItemBuilder, IRestDataSourceItemBuilder - { - //bug: the url is required on the client or it won't work - - DataSource _dataSource; - - public RestDataSourceItemBuilder(string title) : - this(new DataSource(), title) - { } - - public RestDataSourceItemBuilder(DataSource dataSource, string title) : - base(null, DataSourceProvider.JSON, DataSourceProvider.REST, title) - { - _dataSource = dataSource ?? new DataSource(); - DataSource.Id = DataSourceIds.JSON; - DataSourceItem.DataSourceId = DataSource.Id; - UpdateResourceItemDataSource(_dataSource); - } - - public override IDataSourceItemBuilder Fields(IEnumerable fields) - { - DataSourceItem.Parameters.Add("config", BuildConfig(fields)); - return base.Fields(fields); - } - - public IRestDataSourceItemBuilder AddHeader(HeaderType headerType, string value) - { - var propertyKey = "Headers"; - - var headerValue = $"{AddDashesToEnumName(headerType.ToString())}={value}"; - - if (!ResourceItemDataSource.Properties.ContainsKey(propertyKey)) - { - ResourceItemDataSource.Properties.Add(propertyKey, new List { headerValue }); - } - else - { - var headers = (List)ResourceItemDataSource.Properties[propertyKey]; - headers.Add(headerValue); - } - - return this; - } - - public IRestDataSourceItemBuilder IsAnonymous(bool isAnonymous) - { - ResourceItemDataSource.Properties.SetItem("_rpUseAnonymousAuthentication", isAnonymous); - return this; - } - - public IRestDataSourceItemBuilder UseCsv() - { - ClearJsonConfig(); - UpdateDataSourceId(DataSourceIds.CSV); - DataSource.Provider = DataSourceProvider.CSV; - ResourceItemDataSource.Properties.SetItem("Result-Type", ".csv"); - return this; - } - - public IRestDataSourceItemBuilder UseExcel(string sheet = null, ExcelFileType fileType = ExcelFileType.Xlsx) - { - ClearJsonConfig(); - UpdateDataSourceId(DataSourceIds.Excel); - DataSource.Provider = DataSourceProvider.MicrosoftExcel; - - var fileExt = fileType == ExcelFileType.Xlsx ? ".xlsx" : ".xls"; - ResourceItemDataSource.Properties.SetItem("Result-Type", fileExt); - - if (sheet != null) - DataSourceItem.Properties.SetItem("Sheet", sheet); - - return this; - } - - public IRestDataSourceItemBuilder Uri(string uri) - { - ResourceItem.Properties.SetItem("Url", uri); - ResourceItemDataSource.Properties.SetItem("Url", uri); - return this; - } - - public override IDataSourceItemBuilder Id(string id) - { - ResourceItem.Id = id; - return this; - } - - public override IDataSourceItemBuilder Subtitle(string subtitle) - { - base.Subtitle(subtitle); - ResourceItem.Subtitle = subtitle; - return this; - } - - public override IDataSourceItemBuilder ConfigureDataSource(Action configureDataSource) - { - configureDataSource.Invoke(_dataSource); - UpdateResourceItemDataSource(_dataSource); - return this; - } - - //todo: this may need to go on the base class. wait until more builders are created - private void UpdateResourceItemDataSource(DataSource dataSource) - { - ResourceItemDataSource.Id = dataSource.Id; - ResourceItemDataSource.Title = dataSource.Title ?? ResourceItem.Title; - ResourceItemDataSource.Subtitle = dataSource.Subtitle ?? ResourceItem.Subtitle; - ResourceItem.DataSourceId = ResourceItemDataSource.Id; - } - - Dictionary BuildConfig(IEnumerable fields) - { - Dictionary config = new Dictionary(); - List columnConfigs = new List(); - foreach (var field in fields) - { - if (field == null) - continue; - - var columnConfig = new ColumnConfig - { - Key = field.FieldName - }; - - - int type = ((IFieldDataType)field).DataType switch - { - DataType.Number => 1, - DataType.Date => 2, - DataType.DateTime => 3, - DataType.Time => 4, - _ => 0 - }; - - columnConfig.Type = type; - columnConfigs.Add(columnConfig); - } - - config.Add("iterationDepth", 0); - config.Add("columnsConfig", columnConfigs); - return config; - } - - void ClearJsonConfig() - { - if (DataSourceItem.Parameters.ContainsKey("config")) - DataSourceItem.Parameters.Remove("config"); - } - - string AddDashesToEnumName(string name) - { - return string.Concat(name.Select(x => char.IsUpper(x) ? "-" + x : x.ToString())).TrimStart('-'); - } - } -} +using Reveal.Sdk.Dom.Core.Constants; +using Reveal.Sdk.Dom.Core.Extensions; +using Reveal.Sdk.Dom.Visualizations; +using System.Collections.Generic; +using System.Linq; + +namespace Reveal.Sdk.Dom.Data +{ + public class RestDataSourceItem : DataSourceItem + { + DataSource _dataSource; + + public RestDataSourceItem(string title) : this(new DataSource(), title) + { } + + public RestDataSourceItem(DataSource dataSource, string title) : base(null, title) + { + _dataSource = dataSource ?? new DataSource(); + InitializeResourceItem(DataSourceProvider.REST, title); + UpdateResourceItemDataSource(_dataSource); + } + + public bool IsAnonymous + { + get { return ResourceItemDataSource.Properties.GetValue("_rpUseAnonymousAuthentication"); } + set + { + ResourceItemDataSource.Properties.SetItem("_rpUseAnonymousAuthentication", value); + } + } + + public string Uri + { + get { return ResourceItem.Properties.GetValue("Url"); } + set + { + ResourceItem.Properties.SetItem("Url", value); + ResourceItemDataSource.Properties.SetItem("Url", value); + } + } + + public void AddHeader(HeaderType headerType, string value) + { + var propertyKey = "Headers"; + + var headerValue = $"{AddDashesToEnumName(headerType.ToString())}={value}"; + + if (!ResourceItemDataSource.Properties.ContainsKey(propertyKey)) + { + ResourceItemDataSource.Properties.Add(propertyKey, new List { headerValue }); + } + else + { + var headers = (List)ResourceItemDataSource.Properties[propertyKey]; + headers.Add(headerValue); + } + } + + public void UseCsv() + { + ClearJsonConfig(); + UpdateDataSourceId(DataSourceIds.CSV); + DataSource.Provider = DataSourceProvider.CSV; + ResourceItemDataSource.Properties.SetItem("Result-Type", ".csv"); + } + + public void UseExcel(string sheet = null, ExcelFileType fileType = ExcelFileType.Xlsx) + { + ClearJsonConfig(); + UpdateDataSourceId(DataSourceIds.Excel); + DataSource.Provider = DataSourceProvider.MicrosoftExcel; + + var fileExt = fileType == ExcelFileType.Xlsx ? ".xlsx" : ".xls"; + ResourceItemDataSource.Properties.SetItem("Result-Type", fileExt); + + if (sheet != null) + Properties.SetItem("Sheet", sheet); + } + + protected override void InitializeDataSource(DataSource dataSource, string title) + { + base.InitializeDataSource(dataSource, title); + UpdateDataSourceId(DataSourceIds.JSON); + DataSource.Provider = DataSourceProvider.JSON; + } + + protected override void OnFieldsPropertyChanged(List fields) + { + Parameters.Add("config", BuildConfig(fields)); + } + + //todo: this may need to go on the base class. wait until more data source items are created + private void UpdateResourceItemDataSource(DataSource dataSource) + { + ResourceItemDataSource.Id = dataSource.Id; + ResourceItemDataSource.Title = dataSource.Title ?? ResourceItem.Title; + ResourceItemDataSource.Subtitle = dataSource.Subtitle ?? ResourceItem.Subtitle; + ResourceItem.DataSourceId = ResourceItemDataSource.Id; + } + + private Dictionary BuildConfig(IEnumerable fields) + { + Dictionary config = new Dictionary(); + List columnConfigs = new List(); + foreach (var field in fields) + { + if (field == null) + continue; + + var columnConfig = new ColumnConfig + { + Key = field.FieldName + }; + + + int type = ((IFieldDataType)field).DataType switch + { + DataType.Number => 1, + DataType.Date => 2, + DataType.DateTime => 3, + DataType.Time => 4, + _ => 0 + }; + + columnConfig.Type = type; + columnConfigs.Add(columnConfig); + } + + config.Add("iterationDepth", 0); + config.Add("columnsConfig", columnConfigs); + return config; + } + + void ClearJsonConfig() + { + if (Parameters.ContainsKey("config")) + Parameters.Remove("config"); + } + + string AddDashesToEnumName(string name) + { + return string.Concat(name.Select(x => char.IsUpper(x) ? "-" + x : x.ToString())).TrimStart('-'); + } + } +} diff --git a/src/Reveal.Sdk.Dom/Visualizations/Visualization.cs b/src/Reveal.Sdk.Dom/Visualizations/Visualization.cs index bbf83ad..c46d619 100644 --- a/src/Reveal.Sdk.Dom/Visualizations/Visualization.cs +++ b/src/Reveal.Sdk.Dom/Visualizations/Visualization.cs @@ -99,13 +99,16 @@ public DataSourceItem GetDataSourceItem() /// The created with a data source builder. public void UpdateDataSourceItem(DataSourceItem dataSourceItem) { - if (DataDefinition == null) + if (DataDefinition == null || dataSourceItem == null) return; ((DataDefinitionBase)DataDefinition).DataSourceItem = dataSourceItem; if (DataDefinition is TabularDataDefinition tdd) { - tdd.Fields = dataSourceItem?.Fields.Clone(); + if (dataSourceItem.Fields == null || dataSourceItem.Fields.Count == 0) + throw new ArgumentException("Field definitions for the data source item are required. Set the DataSourceitem.Fields property."); + + tdd.Fields = dataSourceItem.Fields.Clone(); } }