Skip to content

Commit c84e13b

Browse files
committed
Add package and browse commands
1 parent 59bbb8f commit c84e13b

32 files changed

+1036
-29
lines changed

src/Dax.Vpax.CLI/.editorconfig

+190
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
# editorconfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
# Default settings:
7+
# A newline ending every file
8+
# Use 4 spaces as indentation
9+
[*]
10+
insert_final_newline = true
11+
indent_style = space
12+
indent_size = 4
13+
trim_trailing_whitespace = true
14+
15+
# Generated code
16+
[*{_AssemblyInfo.cs,.notsupported.cs,AsmOffsets.cs}]
17+
generated_code = true
18+
19+
# C# files
20+
[*.cs]
21+
# New line preferences
22+
csharp_new_line_before_open_brace = all
23+
csharp_new_line_before_else = true
24+
csharp_new_line_before_catch = true
25+
csharp_new_line_before_finally = true
26+
csharp_new_line_before_members_in_object_initializers = true
27+
csharp_new_line_before_members_in_anonymous_types = true
28+
csharp_new_line_between_query_expression_clauses = true
29+
30+
# Indentation preferences
31+
csharp_indent_block_contents = true
32+
csharp_indent_braces = false
33+
csharp_indent_case_contents = true
34+
csharp_indent_case_contents_when_block = true
35+
csharp_indent_switch_labels = true
36+
csharp_indent_labels = one_less_than_current
37+
38+
# Modifier preferences
39+
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:suggestion
40+
41+
# avoid this. unless absolutely necessary
42+
dotnet_style_qualification_for_field = false:suggestion
43+
dotnet_style_qualification_for_property = false:suggestion
44+
dotnet_style_qualification_for_method = false:suggestion
45+
dotnet_style_qualification_for_event = false:suggestion
46+
47+
# Types: use keywords instead of BCL types, and always suggest var
48+
csharp_style_var_for_built_in_types = true:suggestion
49+
csharp_style_var_when_type_is_apparent = true:suggestion
50+
csharp_style_var_elsewhere = true:suggestion
51+
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
52+
dotnet_style_predefined_type_for_member_access = true:suggestion
53+
54+
# name all constant fields using PascalCase
55+
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
56+
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
57+
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
58+
dotnet_naming_symbols.constant_fields.applicable_kinds = field
59+
dotnet_naming_symbols.constant_fields.required_modifiers = const
60+
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
61+
62+
# static fields should have s_ prefix
63+
dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
64+
dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
65+
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
66+
dotnet_naming_symbols.static_fields.applicable_kinds = field
67+
dotnet_naming_symbols.static_fields.required_modifiers = static
68+
dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
69+
dotnet_naming_style.static_prefix_style.required_prefix = s_
70+
dotnet_naming_style.static_prefix_style.capitalization = camel_case
71+
72+
# internal and private fields should be _camelCase
73+
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
74+
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
75+
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
76+
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
77+
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
78+
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
79+
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
80+
81+
# Code style defaults
82+
csharp_using_directive_placement = outside_namespace:suggestion
83+
dotnet_sort_system_directives_first = true
84+
csharp_prefer_braces = true:silent
85+
csharp_preserve_single_line_blocks = true:none
86+
csharp_preserve_single_line_statements = false:none
87+
csharp_prefer_static_local_function = true:suggestion
88+
csharp_prefer_simple_using_statement = false:none
89+
csharp_style_prefer_primary_constructors = false:none
90+
csharp_style_prefer_switch_expression = true:suggestion
91+
dotnet_style_readonly_field = true:suggestion
92+
93+
# Expression-level preferences
94+
dotnet_style_object_initializer = true:suggestion
95+
dotnet_style_collection_initializer = true:suggestion
96+
dotnet_style_explicit_tuple_names = true:suggestion
97+
dotnet_style_coalesce_expression = true:suggestion
98+
dotnet_style_null_propagation = true:suggestion
99+
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
100+
dotnet_style_prefer_inferred_tuple_names = true:suggestion
101+
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
102+
dotnet_style_prefer_auto_properties = true:suggestion
103+
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
104+
dotnet_style_prefer_conditional_expression_over_return = true:silent
105+
csharp_prefer_simple_default_expression = true:suggestion
106+
107+
# Expression-bodied members
108+
csharp_style_expression_bodied_methods = true:silent
109+
csharp_style_expression_bodied_constructors = true:silent
110+
csharp_style_expression_bodied_operators = true:silent
111+
csharp_style_expression_bodied_properties = true:silent
112+
csharp_style_expression_bodied_indexers = true:silent
113+
csharp_style_expression_bodied_accessors = true:silent
114+
csharp_style_expression_bodied_lambdas = true:silent
115+
csharp_style_expression_bodied_local_functions = true:silent
116+
117+
# Pattern matching
118+
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
119+
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
120+
csharp_style_inlined_variable_declaration = true:suggestion
121+
122+
# Null checking preferences
123+
csharp_style_throw_expression = true:suggestion
124+
csharp_style_conditional_delegate_call = true:suggestion
125+
126+
# Other features
127+
csharp_style_prefer_index_operator = false:none
128+
csharp_style_prefer_range_operator = false:none
129+
csharp_style_pattern_local_over_anonymous_function = false:none
130+
131+
# Space preferences
132+
csharp_space_after_cast = false
133+
csharp_space_after_colon_in_inheritance_clause = true
134+
csharp_space_after_comma = true
135+
csharp_space_after_dot = false
136+
csharp_space_after_keywords_in_control_flow_statements = true
137+
csharp_space_after_semicolon_in_for_statement = true
138+
csharp_space_around_binary_operators = before_and_after
139+
csharp_space_around_declaration_statements = do_not_ignore
140+
csharp_space_before_colon_in_inheritance_clause = true
141+
csharp_space_before_comma = false
142+
csharp_space_before_dot = false
143+
csharp_space_before_open_square_brackets = false
144+
csharp_space_before_semicolon_in_for_statement = false
145+
csharp_space_between_empty_square_brackets = false
146+
csharp_space_between_method_call_empty_parameter_list_parentheses = false
147+
csharp_space_between_method_call_name_and_opening_parenthesis = false
148+
csharp_space_between_method_call_parameter_list_parentheses = false
149+
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
150+
csharp_space_between_method_declaration_name_and_open_parenthesis = false
151+
csharp_space_between_method_declaration_parameter_list_parentheses = false
152+
csharp_space_between_parentheses = false
153+
csharp_space_between_square_brackets = false
154+
155+
# License header
156+
# file_header_template =
157+
158+
# C++ Files
159+
[*.{cpp,h,in}]
160+
curly_bracket_next_line = true
161+
indent_brace_style = Allman
162+
163+
# Xml project files
164+
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
165+
indent_size = 2
166+
167+
[*.{csproj,vbproj,proj,nativeproj,locproj}]
168+
charset = utf-8
169+
170+
# Xml build files
171+
[*.builds]
172+
indent_size = 2
173+
174+
# Xml files
175+
[*.{xml,stylecop,resx,ruleset}]
176+
indent_size = 2
177+
178+
# Xml config files
179+
[*.{props,targets,config,nuspec}]
180+
indent_size = 2
181+
182+
# YAML config files
183+
[*.{yml,yaml}]
184+
indent_size = 2
185+
186+
# Shell scripts
187+
[*.sh]
188+
end_of_line = lf
189+
[*.{cmd,bat}]
190+
end_of_line = crlf
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Dax.Vpax.CLI.Commands.Package;
2+
3+
namespace Dax.Vpax.CLI.Commands.Browse;
4+
5+
internal sealed class BrowseColumnCommand : Command
6+
{
7+
public static BrowseColumnCommand Instance { get; } = new BrowseColumnCommand();
8+
9+
private BrowseColumnCommand()
10+
: base(name: "column", description: "Display columns information")
11+
{
12+
AddAlias("c");
13+
Handler = new BrowseColumnCommandHandler();
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
namespace Dax.Vpax.CLI.Commands.Browse;
2+
3+
internal sealed class BrowseColumnCommandHandler : CommandHandler
4+
{
5+
public override Task<int> InvokeAsync(InvocationContext context)
6+
{
7+
var model = GetCurrentModel(context);
8+
if (model is null)
9+
return Task.FromResult(context.ExitCode);
10+
11+
AnsiConsole.Write(GetColumns(context, model));
12+
return Task.FromResult(context.ExitCode);
13+
}
14+
15+
private IRenderable GetColumns(InvocationContext context, Metadata.Model model)
16+
{
17+
var top = context.ParseResult.GetValueForOption(CommonOptions.TopOption);
18+
var excludeHidden = context.ParseResult.GetValueForOption(CommonOptions.ExcludeHiddenOption);
19+
var orderBy = context.ParseResult.GetValueForOption(CommonOptions.OrderByOption);
20+
21+
var table = new Spectre.Console.Table().BorderColor(Color.Yellow)
22+
.AddColumn(new TableColumn(new Markup("[yellow]Name[/]").Centered()).NoWrap())
23+
.AddColumn(new TableColumn(new Markup("[yellow]Cardinality[/]").Centered()))
24+
.AddColumn(new TableColumn(new Markup("[yellow]Size[/]").Centered()))
25+
.AddColumn(new TableColumn(new Markup("[yellow]Size %[/]").Centered()))
26+
.AddColumn(new TableColumn(new Markup("[yellow]Data Size[/]").Centered()))
27+
.AddColumn(new TableColumn(new Markup("[yellow]Dictionary Size[/]").Centered()))
28+
.AddColumn(new TableColumn(new Markup("[yellow]Hierarchies Size[/]").Centered()))
29+
.AddColumn(new TableColumn(new Markup("[yellow]Encoding[/]").Centered()))
30+
.AddColumn(new TableColumn(new Markup("[yellow]Data Type[/]").Centered()));
31+
32+
var query = model.Tables.SelectMany((t) => t.Columns).Where(c => !c.IsRowNumber);
33+
34+
query = orderBy switch
35+
{
36+
"name" or "n" => query.OrderBy((c) => c.ToDisplayName()),
37+
"cardinality" or "c" => query.OrderByDescending((c) => c.ColumnCardinality),
38+
"size" or "s" => query.OrderByDescending((c) => c.TotalSize),
39+
_ => query
40+
};
41+
42+
if (excludeHidden) query = query.Where((c) => !c.IsHidden);
43+
if (top.HasValue) query = query.Take(top.Value);
44+
45+
var modelSize = model.Tables.Sum((t) => t.TableSize);
46+
var columns = query.ToArray();
47+
48+
foreach (var c in columns)
49+
{
50+
var style = c.IsHidden ? new Style(foreground: Color.Grey) : Style.Plain;
51+
var sizePercentage = (double)c.TotalSize / modelSize;
52+
53+
table.AddRow(
54+
new Text(c.ToDisplayName(), style).LeftJustified(),
55+
new Text(c.ColumnCardinality.ToString("N0"), style).RightJustified(),
56+
new Text(c.TotalSize.ToString("N0"), style).RightJustified(),
57+
new Text(sizePercentage.ToString("P2"), style).RightJustified(),
58+
new Text(c.DataSize.ToString("N0"), style).RightJustified(),
59+
new Text(c.DictionarySize.ToString("N0"), style).RightJustified(),
60+
new Text(c.HierarchiesSize.ToString("N0"), style).RightJustified(),
61+
new Text(c.Encoding, style).RightJustified(),
62+
new Text(c.DataType, style).RightJustified()
63+
);
64+
}
65+
66+
table.Columns[0].Footer = new Markup($"[grey]{columns.Length:N0} items[/]").LeftJustified();
67+
table.Columns[1].Footer = new Markup($"[grey]{columns.Sum(_ => _.ColumnCardinality):N0}[/]").RightJustified();
68+
table.Columns[2].Footer = new Markup($"[grey]{columns.Sum(_ => _.TotalSize).ToSizeString():N0}[/]").RightJustified();
69+
table.Columns[4].Footer = new Markup($"[grey]{columns.Sum(_ => _.DataSize).ToSizeString():N0}[/]").RightJustified();
70+
table.Columns[5].Footer = new Markup($"[grey]{columns.Sum(_ => _.DictionarySize).ToSizeString():N0}[/]").RightJustified();
71+
table.Columns[6].Footer = new Markup($"[grey]{columns.Sum(_ => _.HierarchiesSize).ToSizeString():N0}[/]").RightJustified();
72+
73+
return table;
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace Dax.Vpax.CLI.Commands.Browse;
2+
3+
internal sealed class BrowseCommand : Command
4+
{
5+
public static BrowseCommand Instance { get; } = new BrowseCommand();
6+
7+
private BrowseCommand()
8+
: base(name: "browse", description: "(Experimental) Browse metadata of a tabular model in a VPAX package file")
9+
{
10+
AddCommand(BrowseModelCommand.Instance);
11+
AddCommand(BrowseTableCommand.Instance);
12+
AddCommand(BrowseColumnCommand.Instance);
13+
AddCommand(BrowseRelationshipCommand.Instance);
14+
15+
AddGlobalOption(Commands.CommonOptions.PathOption);
16+
AddGlobalOption(CommonOptions.ExcludeHiddenOption);
17+
AddGlobalOption(CommonOptions.OrderByOption);
18+
AddGlobalOption(CommonOptions.TopOption);
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace Dax.Vpax.CLI.Commands.Browse;
2+
3+
internal sealed class BrowseModelCommand : Command
4+
{
5+
public static BrowseModelCommand Instance { get; } = new BrowseModelCommand();
6+
7+
private BrowseModelCommand()
8+
: base(name: "model", description: "Display tabular model information")
9+
{
10+
AddAlias("m");
11+
Handler = new BrowseModelCommandHandler();
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using Spectre.Console;
2+
3+
namespace Dax.Vpax.CLI.Commands.Browse;
4+
5+
internal sealed class BrowseModelCommandHandler : CommandHandler
6+
{
7+
public override Task<int> InvokeAsync(InvocationContext context)
8+
{
9+
var model = GetCurrentModel(context);
10+
if (model is null)
11+
return Task.FromResult(context.ExitCode);
12+
13+
var grid = new Grid()
14+
.AddColumns(1)
15+
.AddRow(GetProperties(model))
16+
.AddEmptyRow()
17+
.AddRow(GetSizeChart(model));
18+
19+
AnsiConsole.Write(new Panel(grid));
20+
return Task.FromResult(context.ExitCode);
21+
}
22+
23+
private IRenderable GetProperties(Metadata.Model model)
24+
{
25+
var table = new Spectre.Console.Table().HideHeaders().Expand().BorderColor(Color.Yellow)
26+
.AddColumn("Name")
27+
.AddColumn("Value")
28+
.AddRow("[yellow]Model[/]", model.ModelName.Name)
29+
.AddRow("[yellow]Compatibility Level[/]", model.CompatibilityLevel.ToString())
30+
.AddRow("[yellow]Compatibility Mode[/]", model.CompatibilityMode.ToEmptyIfNull())
31+
.AddRow("[yellow]Version[/]", model.Version.ToString())
32+
.AddRow("[yellow]Culture[/]", model.Culture.ToEmptyIfNull())
33+
.AddRow("[yellow]Last Refresh[/]", model.LastDataRefresh.ToString("o", CultureInfo.InvariantCulture))
34+
.AddRow("[yellow]Last Process[/]", model.LastProcessed.ToString("o", CultureInfo.InvariantCulture))
35+
.AddRow("[yellow]Last Update[/]", model.LastUpdate.ToString("o", CultureInfo.InvariantCulture))
36+
.AddRow("[yellow]Tables[/]", model.Tables.Count.ToString())
37+
.AddRow("[yellow]Columns[/]", model.Tables.SelectMany((t) => t.Columns).Where(c => !c.IsRowNumber).Count().ToString())
38+
.AddRow("[yellow]Size (in memory)[/]", model.Tables.Sum((t) => t.TableSize).ToSizeString());
39+
40+
return table;
41+
}
42+
43+
private IRenderable GetSizeChart(Metadata.Model model)
44+
{
45+
var dataSize = model.Tables.Sum((t) => t.ColumnsDataSize);
46+
var dictionariesSize = model.Tables.Sum((t) => t.ColumnsDictionarySize);
47+
var hierarchiesSize = model.Tables.Sum((t) => t.ColumnsHierarchiesSize);
48+
var totalSize = dataSize + dictionariesSize + hierarchiesSize;
49+
50+
var dataPercentage = Math.Floor((double)dataSize / totalSize * 100);
51+
var dictionariePercentage = Math.Floor((double)dictionariesSize / totalSize * 100);
52+
var hierarchiesPercentage = 100 - dataPercentage - dictionariePercentage;
53+
54+
var chart = new BreakdownChart().ShowPercentage().FullSize()
55+
.AddItem("Data", dataPercentage, Color.Red)
56+
.AddItem("Dictionary", dictionariePercentage, Color.Green)
57+
.AddItem("Hierarchy", hierarchiesPercentage, Color.Blue);
58+
59+
return chart;
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Dax.Vpax.CLI.Commands.Package;
2+
3+
namespace Dax.Vpax.CLI.Commands.Browse;
4+
5+
internal sealed class BrowseRelationshipCommand : Command
6+
{
7+
public static BrowseRelationshipCommand Instance { get; } = new BrowseRelationshipCommand();
8+
9+
private BrowseRelationshipCommand()
10+
: base(name: "relationship", description: "Display relationships information")
11+
{
12+
AddAlias("r");
13+
Handler = new BrowseRelationshipCommandHandler();
14+
}
15+
}

0 commit comments

Comments
 (0)