Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor browse and package command args for CLI tool #194

Merged
merged 7 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/Dax.Vpax.CLI/Commands/Browse/BrowseColumnCommand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Dax.Vpax.CLI.Commands.Package;
using static Dax.Vpax.CLI.Commands.Browse.BrowseColumnCommandOptions;

namespace Dax.Vpax.CLI.Commands.Browse;

Expand All @@ -7,9 +7,26 @@ internal sealed class BrowseColumnCommand : Command
public static BrowseColumnCommand Instance { get; } = new BrowseColumnCommand();

private BrowseColumnCommand()
: base(name: "column", description: "Display columns information")
: base(name: "column", description: "Display column information")
{
AddAlias("c");
AddOption(CommonOptions.VpaxOption);
AddOption(TableOption);
AddOption(CommonOptions.ExcludeHiddenOption);
AddOption(CommonOptions.OrderByOption);
AddOption(CommonOptions.TopOption);

Handler = new BrowseColumnCommandHandler();
}
}

internal static class BrowseColumnCommandOptions
{
public static readonly Option<string> TableOption = new(
name: "--table",
description: "Specify the table name"
)
{
ArgumentHelpName = "name"
};
}
113 changes: 72 additions & 41 deletions src/Dax.Vpax.CLI/Commands/Browse/BrowseColumnCommandHandler.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
namespace Dax.Vpax.CLI.Commands.Browse;
using static Dax.Vpax.CLI.Commands.Browse.BrowseColumnCommandOptions;

namespace Dax.Vpax.CLI.Commands.Browse;

internal sealed class BrowseColumnCommandHandler : CommandHandler
{
public override Task<int> InvokeAsync(InvocationContext context)
{
var model = GetCurrentModel(context);
if (model is null)
return Task.FromResult(context.ExitCode);
var vpax = context.ParseResult.GetValueForOption(CommonOptions.VpaxOption)!;

var model = GetModel(context, vpax);
if (model is not null)
{
AnsiConsole.Write(GetView(context, model));
}

AnsiConsole.Write(GetColumns(context, model));
return Task.FromResult(context.ExitCode);
}

private IRenderable GetColumns(InvocationContext context, Metadata.Model model)
private IRenderable GetView(InvocationContext context, Metadata.Model model)
{
var top = context.ParseResult.GetValueForOption(CommonOptions.TopOption);
var excludeHidden = context.ParseResult.GetValueForOption(CommonOptions.ExcludeHiddenOption);
var orderBy = context.ParseResult.GetValueForOption(CommonOptions.OrderByOption);
var top = context.ParseResult.GetValueForOption(CommonOptions.TopOption);
var table = context.ParseResult.GetValueForOption(TableOption);

var table = new Spectre.Console.Table().BorderColor(Color.Yellow)
var view = new Spectre.Console.Table().BorderColor(Color.Yellow)
.AddColumn(new TableColumn(new Markup("[yellow]Name[/]").Centered()).NoWrap())
.AddColumn(new TableColumn(new Markup("[yellow]Cardinality[/]").Centered()))
.AddColumn(new TableColumn(new Markup("[yellow]Size[/]").Centered()))
Expand All @@ -29,47 +35,72 @@ private IRenderable GetColumns(InvocationContext context, Metadata.Model model)
.AddColumn(new TableColumn(new Markup("[yellow]Encoding[/]").Centered()))
.AddColumn(new TableColumn(new Markup("[yellow]Data Type[/]").Centered()));

var query = model.Tables.SelectMany((t) => t.Columns).Where(c => !c.IsRowNumber);

query = orderBy switch
var totalSize = model.Tables.Sum((t) => t.TableSize);
var query = model.Tables.Where((t) => table is null || table.Equals(t.TableName.Name, StringComparison.OrdinalIgnoreCase)).SelectMany((t) => t.Columns).Where((c) => !c.IsRowNumber).Select((t) => new Row(t, totalSize));
if (orderBy.HasValue)
{
"name" or "n" => query.OrderBy((c) => c.ToDisplayName()),
"cardinality" or "c" => query.OrderByDescending((c) => c.ColumnCardinality),
"size" or "s" => query.OrderByDescending((c) => c.TotalSize),
_ => query
};

if (excludeHidden) query = query.Where((c) => !c.IsHidden);
query = orderBy switch
{
-1 => query.OrderByDescending(_ => _.Name),
+1 => query.OrderBy(_ => _.Name),
2 => query.OrderByDescending(_ => _.Cardinality),
3 => query.OrderByDescending(_ => _.Size),
4 => query.OrderByDescending(_ => _.SizePercentage),
5 => query.OrderByDescending(_ => _.DataSize),
6 => query.OrderByDescending(_ => _.DictionarySize),
7 => query.OrderByDescending(_ => _.HierarchiesSize),
-8 => query.OrderByDescending(_ => _.Encoding),
+8 => query.OrderBy(_ => _.Encoding),
-9 => query.OrderByDescending(_ => _.DataType),
+9 => query.OrderBy(_ => _.DataType),
_ => query.OrderByDescending(_ => 0), // ignore invalid order by
};
}
if (excludeHidden) query = query.Where((r) => !r.IsHidden);
if (top.HasValue) query = query.Take(top.Value);

var modelSize = model.Tables.Sum((t) => t.TableSize);
var columns = query.ToArray();

foreach (var c in columns)
var rows = query.ToArray();
foreach (var r in rows)
{
var style = c.IsHidden ? new Style(foreground: Color.Grey) : Style.Plain;
var sizePercentage = (double)c.TotalSize / modelSize;
var style = r.IsHidden ? new Style(foreground: Color.Grey) : Style.Plain;

table.AddRow(
new Text(c.ToDisplayName(), style).LeftJustified(),
new Text(c.ColumnCardinality.ToString("N0"), style).RightJustified(),
new Text(c.TotalSize.ToString("N0"), style).RightJustified(),
new Text(sizePercentage.ToString("P2"), style).RightJustified(),
new Text(c.DataSize.ToString("N0"), style).RightJustified(),
new Text(c.DictionarySize.ToString("N0"), style).RightJustified(),
new Text(c.HierarchiesSize.ToString("N0"), style).RightJustified(),
new Text(c.Encoding, style).RightJustified(),
new Text(c.DataType, style).RightJustified()
view.AddRow(
new Text(r.Name, style).LeftJustified(),
new Text(r.Cardinality.ToString("N0"), style).RightJustified(),
new Text(r.Size.ToString("N0"), style).RightJustified(),
new Text(r.SizePercentage.ToString("P2"), style).RightJustified(),
new Text(r.DataSize.ToString("N0"), style).RightJustified(),
new Text(r.DictionarySize.ToString("N0"), style).RightJustified(),
new Text(r.HierarchiesSize.ToString("N0"), style).RightJustified(),
new Text(r.Encoding, style).RightJustified(),
new Text(r.DataType, style).RightJustified()
);
}

table.Columns[0].Footer = new Markup($"[grey]{columns.Length:N0} items[/]").LeftJustified();
table.Columns[1].Footer = new Markup($"[grey]{columns.Sum(_ => _.ColumnCardinality):N0}[/]").RightJustified();
table.Columns[2].Footer = new Markup($"[grey]{columns.Sum(_ => _.TotalSize).ToSizeString():N0}[/]").RightJustified();
table.Columns[4].Footer = new Markup($"[grey]{columns.Sum(_ => _.DataSize).ToSizeString():N0}[/]").RightJustified();
table.Columns[5].Footer = new Markup($"[grey]{columns.Sum(_ => _.DictionarySize).ToSizeString():N0}[/]").RightJustified();
table.Columns[6].Footer = new Markup($"[grey]{columns.Sum(_ => _.HierarchiesSize).ToSizeString():N0}[/]").RightJustified();
view.Columns[0].Footer = new Markup($"[grey]{rows.Length:N0} items[/]").LeftJustified();
view.Columns[1].Footer = new Markup($"[grey]{rows.Sum(_ => _.Cardinality):N0}[/]").RightJustified();
view.Columns[2].Footer = new Markup($"[grey]{rows.Sum(_ => _.Size).ToSizeString():N0}[/]").RightJustified();
// table.Columns[3].Footer = // SizePercentage
view.Columns[4].Footer = new Markup($"[grey]{rows.Sum(_ => _.DataSize).ToSizeString():N0}[/]").RightJustified();
view.Columns[5].Footer = new Markup($"[grey]{rows.Sum(_ => _.DictionarySize).ToSizeString():N0}[/]").RightJustified();
view.Columns[6].Footer = new Markup($"[grey]{rows.Sum(_ => _.HierarchiesSize).ToSizeString():N0}[/]").RightJustified();
// table.Columns[7].Footer = // Encoding
// table.Columns[8].Footer = // DataType

return table;
return view;
}

private sealed record Row(Metadata.Column column, long totalSize)
{
public bool IsHidden => column.IsHidden;
public string Name => column.ToDisplayName();
public long Cardinality => column.ColumnCardinality;
public long Size => column.TotalSize;
public double SizePercentage => (double)column.TotalSize / totalSize;
public long DataSize => column.DataSize;
public long DictionarySize => column.DictionarySize;
public long HierarchiesSize => column.HierarchiesSize;
public string Encoding => column.Encoding;
public string DataType => column.DataType;
}
}
5 changes: 0 additions & 5 deletions src/Dax.Vpax.CLI/Commands/Browse/BrowseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,5 @@ private BrowseCommand()
AddCommand(BrowseTableCommand.Instance);
AddCommand(BrowseColumnCommand.Instance);
AddCommand(BrowseRelationshipCommand.Instance);

AddGlobalOption(Commands.CommonOptions.PathOption);
AddGlobalOption(CommonOptions.ExcludeHiddenOption);
AddGlobalOption(CommonOptions.OrderByOption);
AddGlobalOption(CommonOptions.TopOption);
}
}
2 changes: 2 additions & 0 deletions src/Dax.Vpax.CLI/Commands/Browse/BrowseModelCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ private BrowseModelCommand()
: base(name: "model", description: "Display tabular model information")
{
AddAlias("m");
AddOption(CommonOptions.VpaxOption);

Handler = new BrowseModelCommandHandler();
}
}
41 changes: 21 additions & 20 deletions src/Dax.Vpax.CLI/Commands/Browse/BrowseModelCommandHandler.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
using Spectre.Console;

namespace Dax.Vpax.CLI.Commands.Browse;
namespace Dax.Vpax.CLI.Commands.Browse;

internal sealed class BrowseModelCommandHandler : CommandHandler
{
public override Task<int> InvokeAsync(InvocationContext context)
{
var model = GetCurrentModel(context);
if (model is null)
return Task.FromResult(context.ExitCode);
var vpax = context.ParseResult.GetValueForOption(CommonOptions.VpaxOption)!;

var model = GetModel(context, vpax);
if (model is not null)
{
var grid = new Grid()
.AddColumns(1)
.AddRow(GetTableView(model))
.AddEmptyRow()
.AddRow(GetChartView(model));

var grid = new Grid()
.AddColumns(1)
.AddRow(GetProperties(model))
.AddEmptyRow()
.AddRow(GetSizeChart(model));
AnsiConsole.Write(new Panel(grid));
}

AnsiConsole.Write(new Panel(grid));
return Task.FromResult(context.ExitCode);
}

private IRenderable GetProperties(Metadata.Model model)
private IRenderable GetTableView(Metadata.Model model)
{
var table = new Spectre.Console.Table().HideHeaders().Expand().BorderColor(Color.Yellow)
.AddColumn("Name")
Expand All @@ -34,26 +35,26 @@ private IRenderable GetProperties(Metadata.Model model)
.AddRow("[yellow]Last Process[/]", model.LastProcessed.ToString("o", CultureInfo.InvariantCulture))
.AddRow("[yellow]Last Update[/]", model.LastUpdate.ToString("o", CultureInfo.InvariantCulture))
.AddRow("[yellow]Tables[/]", model.Tables.Count.ToString())
.AddRow("[yellow]Columns[/]", model.Tables.SelectMany((t) => t.Columns).Where(c => !c.IsRowNumber).Count().ToString())
.AddRow("[yellow]Columns[/]", model.Tables.SelectMany((t) => t.Columns).Count(c => !c.IsRowNumber).ToString())
.AddRow("[yellow]Size (in memory)[/]", model.Tables.Sum((t) => t.TableSize).ToSizeString());

return table;
}

private IRenderable GetSizeChart(Metadata.Model model)
private IRenderable GetChartView(Metadata.Model model)
{
var dataSize = model.Tables.Sum((t) => t.ColumnsDataSize);
var dictionariesSize = model.Tables.Sum((t) => t.ColumnsDictionarySize);
var dictionarySize = model.Tables.Sum((t) => t.ColumnsDictionarySize);
var hierarchiesSize = model.Tables.Sum((t) => t.ColumnsHierarchiesSize);
var totalSize = dataSize + dictionariesSize + hierarchiesSize;
var totalSize = dataSize + dictionarySize + hierarchiesSize;

var dataPercentage = Math.Floor((double)dataSize / totalSize * 100);
var dictionariePercentage = Math.Floor((double)dictionariesSize / totalSize * 100);
var hierarchiesPercentage = 100 - dataPercentage - dictionariePercentage;
var dictionaryPercentage = Math.Floor((double)dictionarySize / totalSize * 100);
var hierarchiesPercentage = 100 - dataPercentage - dictionaryPercentage;

var chart = new BreakdownChart().ShowPercentage().FullSize()
.AddItem("Data", dataPercentage, Color.Red)
.AddItem("Dictionary", dictionariePercentage, Color.Green)
.AddItem("Dictionary", dictionaryPercentage, Color.Green)
.AddItem("Hierarchy", hierarchiesPercentage, Color.Blue);

return chart;
Expand Down
11 changes: 7 additions & 4 deletions src/Dax.Vpax.CLI/Commands/Browse/BrowseRelationshipCommand.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
using Dax.Vpax.CLI.Commands.Package;

namespace Dax.Vpax.CLI.Commands.Browse;
namespace Dax.Vpax.CLI.Commands.Browse;

internal sealed class BrowseRelationshipCommand : Command
{
public static BrowseRelationshipCommand Instance { get; } = new BrowseRelationshipCommand();

private BrowseRelationshipCommand()
: base(name: "relationship", description: "Display relationships information")
: base(name: "relationship", description: "Display relationship information")
{
AddAlias("r");
AddOption(CommonOptions.VpaxOption);
AddOption(CommonOptions.ExcludeHiddenOption);
AddOption(CommonOptions.OrderByOption);
AddOption(CommonOptions.TopOption);

Handler = new BrowseRelationshipCommandHandler();
}
}
Loading