Skip to content

Commit

Permalink
Enable VPAX extraction on non-Windows platforms (#126)
Browse files Browse the repository at this point in the history
* Remove `windows` platform target

* Use DbConnectionStringBuilder instead of OleDb

* Remove `System.Data.OleDb` package reference

* Fix build error
  • Loading branch information
albertospelta authored Jul 5, 2024
1 parent 7a1209b commit c01b9d9
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 72 deletions.
46 changes: 46 additions & 0 deletions src/Dax.Model.Extractor/Data/ConnectionStringUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Data.Common;
using System.Globalization;

namespace Dax.Model.Extractor.Data
{
public static class ConnectionStringUtils
{
public static string GetDataSource(string connectionString) => GetValue(connectionString, ConnectionStringKeywords.DataSource);

public static string GetInitialCatalog(string connectionString) => GetValue(connectionString, ConnectionStringKeywords.InitialCatalog);

public static string GetConnectionString(string serverNameOrConnectionString, string databaseName)
{
var builder = new DbConnectionStringBuilder(useOdbcRules: false);
try {
builder.ConnectionString = serverNameOrConnectionString;
}
catch {
// Assume servername
builder[ConnectionStringKeywords.Provider] = "MSOLAP";
builder[ConnectionStringKeywords.DataSource] = serverNameOrConnectionString;
}
builder[ConnectionStringKeywords.InitialCatalog] = databaseName;
return builder.ConnectionString;
}

private static string GetValue(string connectionString, string keyword)
{
var builder = new DbConnectionStringBuilder(useOdbcRules: false);
builder.ConnectionString = connectionString;

if (builder.TryGetValue(keyword, out object value))
return ((IConvertible)value).ToString(CultureInfo.InvariantCulture);

return string.Empty; // default to empty string to keep the result consistent with the OleDbConnectionStringBuilder
}
}

internal static class ConnectionStringKeywords
{
public const string Provider = "Provider";
public const string DataSource = "Data Source";
public const string InitialCatalog = "Initial Catalog";
}
}
20 changes: 0 additions & 20 deletions src/Dax.Model.Extractor/Data/IDbConnectionExtensions.cs

This file was deleted.

5 changes: 2 additions & 3 deletions src/Dax.Model.Extractor/Dax.Model.Extractor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net462;netcoreapp3.1;net6.0-windows</TargetFrameworks>
<TargetFrameworks>net462;netcoreapp3.1;net6.0</TargetFrameworks>
<IsPackable>true</IsPackable>
</PropertyGroup>

Expand All @@ -22,13 +22,12 @@

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<PackageReference Include="System.Data.OleDb" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="Microsoft.AnalysisServices.retail.amd64" />
<PackageReference Include="Microsoft.AnalysisServices.AdomdClient.retail.amd64" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1' OR '$(TargetFramework)' == 'net6.0-windows'">
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1' OR '$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.AnalysisServices.NetCore.retail.amd64" />
<PackageReference Include="Microsoft.AnalysisServices.AdomdClient.NetCore.retail.amd64" />
</ItemGroup>
Expand Down
4 changes: 3 additions & 1 deletion src/Dax.Model.Extractor/DmvExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ public class DmvExtractor

protected IDbCommand CreateCommand(string commandText)
{
return Connection.CreateCommand(commandText);
var command = Connection.CreateCommand();
command.CommandText = commandText;
return command;
}

public DmvExtractor(Dax.Metadata.Model daxModel, IDbConnection connection, string serverName, string databaseName, string extractorApp, string extractorVersion)
Expand Down
4 changes: 3 additions & 1 deletion src/Dax.Model.Extractor/StatExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ private StatExtractor(Dax.Metadata.Model daxModel, IDbConnection connection)

protected IDbCommand CreateCommand(string commandText)
{
return Connection.CreateCommand(commandText);
var command = Connection.CreateCommand();
command.CommandText = commandText;
return command;
}

// UpdateStatisticsModel has been marked as obsolete because its usage may require rerunning the DMVs for models with DirectLake partitions. Since this logic should be handled by the library, we may consider removing it from the public APIs in a future release.
Expand Down
40 changes: 7 additions & 33 deletions src/Dax.Model.Extractor/TomExtractor.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using Dax.Metadata;
using Dax.Model.Extractor.Data;
using Microsoft.AnalysisServices.AdomdClient;
using Newtonsoft.Json.Linq;
using System;
using System.Data.OleDb;
using System.Data.Common;
using System.Globalization;
using System.Linq;
using Tom = Microsoft.AnalysisServices.Tabular;

Expand Down Expand Up @@ -288,7 +291,7 @@ public static Dax.Metadata.Model GetDaxModel(string connectionString, string app
var database = GetDatabase(connectionString);
Tom.Model tomModel = database.Model;
string databaseName = database.Name;
string serverName = GetDataSource(connectionString);
string serverName = ConnectionStringUtils.GetDataSource(connectionString);

var daxModel = TomExtractor.GetDaxModel(tomModel, applicationName, applicationVersion);

Expand All @@ -312,18 +315,6 @@ public static Dax.Metadata.Model GetDaxModel(string connectionString, string app
return daxModel;
}

private static string GetDataSource(string connectionString)
{
var builder = new OleDbConnectionStringBuilder(connectionString);
return builder.DataSource;
}

private static string GetInitialCatalog(string connectionString)
{
var builder = new OleDbConnectionStringBuilder(connectionString);
builder.TryGetValue("Initial Catalog", out object initialCatalog);
return initialCatalog.ToString();
}
public static Tom.Database GetDatabase(string serverName, string databaseName)
{
Tom.Server server = new();
Expand All @@ -337,7 +328,7 @@ public static Tom.Database GetDatabase(string connectionString)
{
Tom.Server server = new();
server.Connect(connectionString);
var databaseName = GetInitialCatalog(connectionString);
var databaseName = ConnectionStringUtils.GetInitialCatalog(connectionString);
Tom.Database db = server.Databases.FindByName(databaseName);
// if db is null either it does not exist or we do not have admin rights to it
return db ?? throw new ArgumentException($"The database '{databaseName}' could not be found. Either it does not exist or you do not have admin rights to it.");
Expand All @@ -350,7 +341,7 @@ public static Dax.Metadata.Model GetDaxModel(string serverName, string databaseN

var daxModel = TomExtractor.GetDaxModel(tomModel, applicationName, applicationVersion);

string connectionString = GetConnectionString(serverName, databaseName);
string connectionString = ConnectionStringUtils.GetConnectionString(serverName, databaseName);

using (AdomdConnection connection = new(connectionString))
{
Expand All @@ -371,22 +362,5 @@ public static Dax.Metadata.Model GetDaxModel(string serverName, string databaseN
}
return daxModel;
}

private static string GetConnectionString(string dataSourceOrConnectionString, string databaseName)
{
OleDbConnectionStringBuilder csb = new();
try
{
csb.ConnectionString = dataSourceOrConnectionString;
}
catch
{
// Assume servername
csb.Provider = "MSOLAP";
csb.DataSource = dataSourceOrConnectionString;
}
csb["Initial Catalog"] = databaseName;
return csb.ConnectionString;
}
}
}
16 changes: 9 additions & 7 deletions src/Dax.Vpax.CLI/Commands/ExportCommandOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.CommandLine;
using System.Data.OleDb;
using System.Data.Common;

namespace Dax.Vpax.CLI.Commands;

Expand All @@ -11,12 +11,14 @@ internal static class ExportCommandOptions
parse: (result) =>
{
var connectionString = result.Tokens.Single().Value;

var builder = new OleDbConnectionStringBuilder(connectionString);
if (!builder.ContainsKey("Initial Catalog"))
result.ErrorMessage = "The connection string does not contain the 'Initial Catalog' property.";

return connectionString;
{
var builder = new DbConnectionStringBuilder(useOdbcRules: false);
builder.ConnectionString = connectionString;

if (!builder.ContainsKey("Initial Catalog"))
result.ErrorMessage = "The connection string does not contain the 'Initial Catalog' property.";
}
return connectionString; // always return the original value
});

public static readonly Argument<string> PathArgument = new(
Expand Down
1 change: 0 additions & 1 deletion src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
<PackageVersion Include="Microsoft.AnalysisServices.AdomdClient.NetCore.retail.amd64" Version="$(MicrosoftAnalysisServicesVersion)" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="System.Data.OleDb" Version="6.0.0" />
<PackageVersion Include="System.IO.Packaging" Version="6.0.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
Expand Down
6 changes: 3 additions & 3 deletions utils/TestDaxWpf/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,17 @@ public static Dax.Metadata.Model GetDaxModel(string serverName, string databaseN
server.Connect(serverName);
Microsoft.AnalysisServices.Database db = server.Databases[databaseName];
Microsoft.AnalysisServices.Tabular.Model tomModel = db.Model;
var daxModel = Dax.Metadata.Extractor.TomExtractor.GetDaxModel(tomModel, "TestDaxModel", "0.1");
var daxModel = Dax.Model.Extractor.TomExtractor.GetDaxModel(tomModel, "TestDaxModel", "0.1");

var connectionString = GetConnectionString(serverName, databaseName);

using (var connection = new AdomdConnection(connectionString)) {
// Populate statistics from DMV
Dax.Metadata.Extractor.DmvExtractor.PopulateFromDmv(daxModel, connection, serverName, databaseName, "TestDaxModel", "0.1");
Dax.Model.Extractor.DmvExtractor.PopulateFromDmv(daxModel, connection, serverName, databaseName, "TestDaxModel", "0.1");

// Populate statistics by querying the data model
if (readStatisticsFromData) {
Dax.Metadata.Extractor.StatExtractor.UpdateStatisticsModel(daxModel, connection, 10);
Dax.Model.Extractor.StatExtractor.UpdateStatisticsModel(daxModel, connection, 10);
}
}
return daxModel;
Expand Down
2 changes: 1 addition & 1 deletion utils/TestPowerBI/Form1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ private void TestPbiShared(string name, string id)
//Console.WriteLine("Connection open");

Dax.Metadata.Model m = new Dax.Metadata.Model();
Dax.Metadata.Extractor.DmvExtractor.PopulateFromDmv(m, conn, serverName, databaseName, "Test", "0.1");
Dax.Model.Extractor.DmvExtractor.PopulateFromDmv(m, conn, serverName, databaseName, "Test", "0.1");

Dax.Vpax.Tools.VpaxTools.ExportVpax(@"c:\temp\" + name + ".vpax",m);
}
Expand Down
4 changes: 2 additions & 2 deletions utils/TestWpfPowerBI/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,8 @@ private Dax.ViewModel.VpaModel GetVpaModel(string groupName, string datasetName,
Dax.Metadata.Model m = new Dax.Metadata.Model();
// NOTE: groupName is the serverName in the arguments
// datasetName is the databaseName in the arguments
Dax.Metadata.Extractor.DmvExtractor.PopulateFromDmv(m, conn, groupName, datasetName, "Test", "0.1");
Dax.Metadata.Extractor.StatExtractor.UpdateStatisticsModel(m, conn, 4);
Dax.Model.Extractor.DmvExtractor.PopulateFromDmv(m, conn, groupName, datasetName, "Test", "0.1");
Dax.Model.Extractor.StatExtractor.UpdateStatisticsModel(m, conn, 4);
return new Dax.ViewModel.VpaModel(m);
}

Expand Down

0 comments on commit c01b9d9

Please sign in to comment.