/// <summary> /// Creates a simple model for unit testing. /// </summary> /// <remarks> /// The model will contain: /// - 1 data source: "Test Datasource" /// - 2 roles: "Test Role 1", "Test Role 2" /// - 2 cultures: "da-DK", "en-US" (all objects translated in these) /// - 2 perspectives: "Test Perspective 1", "Test Perspective 2" /// - 2 tables: "Test Table 1", "Test Table 2" /// - 1 calculated table: "Test CalcTable 1" /// - "Test Table 1" contains: /// - 3 columns, 1 calculated column /// - 1 hierarchy (4 levels - one per column) /// - 2 measures, 1 with kpi /// - "Test Table 2" contains: /// - 3 columns, 1 calculated column /// - 1 hierarchy /// - 1 relationship /// </remarks> /// <param name="fileName">If specified, the model will be saved to this file.</param> /// <param name="compatibilityLevel">Specify the compatibility level of the created model.</param> public static TabularModelHandler CreateTestModel(string fileName = null, int compatibilityLevel = 1200) { var tm = new TabularModelHandler(compatibilityLevel); var ds = tm.Model.AddDataSource("Test Datasource"); ds.ConnectionString = "Provider=MSOLEDBSQL;Data Source=localhost;Initial Catalog=db"; var r1 = tm.Model.AddRole("Test Role 1"); var r2 = tm.Model.AddRole("Test Role 2"); var c1 = tm.Model.AddTranslation("da-DK"); var c2 = tm.Model.AddTranslation("en-US"); var p1 = tm.Model.AddPerspective("Test Perspective 1"); var p2 = tm.Model.AddPerspective("Test Perspective 2"); var t1 = tm.Model.AddTable("Test Table 1"); var t2 = tm.Model.AddTable("Test Table 2"); // Create calculated table based on table 2: var t3 = tm.Model.AddCalculatedTable("Test CalcTable 1", @"DATATABLE ( ""String Column"", STRING, ""Decimal Column"", CURRENCY, ""Int Column"", INTEGER, ""Date Column"", DATETIME, ""Boolean Column"", BOOLEAN, ""Double Column"", DOUBLE, { { ""Category A"", -50.1234, -5, ""2017-01-01"", TRUE, 5.134E17 }, { ""Category B"", 3.1415, 2, ""2017-01-02"", FALSE, 9.761E-12 }, { ""Category C"", 45.9876, 8, ""2017-01-03"", TRUE, 1.654 }, { """", 0, 0, 0, FALSE, 0}, { , , , , , } } )"); var c11 = t1.AddDataColumn("Column 1"); var c12 = t1.AddDataColumn("Column 2"); var c13 = t1.AddDataColumn("Column 3"); var c14 = t1.AddCalculatedColumn("Column 4", "[Column 1]"); var h1 = t1.AddHierarchy("Hierarchy 1", null, c11, c12, c13, c14); h1.Levels[0].Name = "Level 1"; h1.Levels[1].Name = "Level 2"; h1.Levels[2].Name = "Level 3"; h1.Levels[3].Name = "Level 4"; var c21 = t2.AddDataColumn("Column 1"); var c22 = t2.AddDataColumn("Column 2"); var c23 = t2.AddDataColumn("Column 3"); var c24 = t2.AddCalculatedColumn("Column 4", "[Column 1]"); var h2 = t2.AddHierarchy("Hierarchy 1", null, c21, c22, c23, c24); var r = tm.Model.AddRelationship(); r.FromColumn = c11; r.ToColumn = c21; var m1 = t1.AddMeasure("Measure 1", "sum('Test CalcTable 1'[Decimal Column])"); var m2 = t1.AddMeasure("Measure 2", "sum('Test CalcTable 1'[Int Column])"); var k1 = m1.AddKPI(); // Apply translations to all items in table 1: var items = t1.GetChildren().Concat(t1.AllLevels).Concat(Enumerable.Repeat(t1, 1)); foreach (var item in items.OfType <ITranslatableObject>()) { item.TranslatedNames["da-DK"] = item.Name + " DK"; item.TranslatedNames["en-US"] = item.Name + " US"; } // Include all items in table 1 in perspective: foreach (var item in t1.GetChildren().OfType <ITabularPerspectiveObject>()) { item.InPerspective.All(); } if (!string.IsNullOrEmpty(fileName)) { tm.Save(fileName, SaveFormat.ModelSchemaOnly, SerializeOptions.Default); } return(tm); }
static bool HandleCommandLine(string[] args) { var upperArgList = args.Select(arg => arg.ToUpper()).ToList(); var argList = args.Select(arg => arg).ToList(); if (upperArgList.Contains("-?") || upperArgList.Contains("/?") || upperArgList.Contains("-H") || upperArgList.Contains("/H") || upperArgList.Contains("HELP")) { OutputUsage(); return(true); } enableVSTS = upperArgList.IndexOf("-VSTS") > -1 || upperArgList.IndexOf("-V") > -1; var warnOnUnprocessed = upperArgList.IndexOf("-WARN") > -1 || upperArgList.IndexOf("-W") > -1; if (!File.Exists(args[1]) && !File.Exists(args[1] + "\\database.json")) { Error("File not found: {0}", args[1]); return(true); } else { // If the file specified as 1st argument exists, and nothing else was specified on the command-line, open the UI: if (args.Length == 2) { return(false); } } var fileName = args[1]; string script = null; string scriptFile = null; var doScript = upperArgList.IndexOf("-SCRIPT"); if (doScript == -1) { doScript = upperArgList.IndexOf("-S"); } if (doScript > -1) { if (upperArgList.Count <= doScript) { Error("Invalid argument syntax.\n"); OutputUsage(); return(true); } scriptFile = argList[doScript + 1]; if (!File.Exists(scriptFile)) { Error("Specified script file not found.\n"); return(true); } script = File.ReadAllText(scriptFile); } string buildOutputPath = null; var doSave = upperArgList.IndexOf("-BUILD"); if (doSave == -1) { doSave = upperArgList.IndexOf("-B"); } if (doSave > -1) { if (upperArgList.Count <= doSave) { Error("Invalid argument syntax.\n"); OutputUsage(); return(true); } buildOutputPath = argList[doSave + 1]; var directoryName = new FileInfo(buildOutputPath).Directory.FullName; Directory.CreateDirectory(directoryName); } // Load model: cw.WriteLine("Loading model..."); var h = new TOMWrapper.TabularModelHandler(fileName); h.Tree = new TOMWrapper.NullTree(); if (!string.IsNullOrEmpty(script)) { cw.WriteLine("Executing script..."); System.CodeDom.Compiler.CompilerResults result; Scripting.ScriptOutputForm.Reset(false); var dyn = ScriptEngine.CompileScript(script, out result); if (result.Errors.Count > 0) { cw.WriteLine("Script compilation errors:"); foreach (System.CodeDom.Compiler.CompilerError err in result.Errors) { ErrorX(err.ErrorText, scriptFile, err.Line, err.Column, err.ErrorNumber); } return(true); } try { dyn.Invoke(h.Model, null); } catch (Exception ex) { Error("Script execution error: " + ex.Message); return(true); } } if (!string.IsNullOrEmpty(buildOutputPath)) { cw.WriteLine("Building Model.bim file..."); h.Save(buildOutputPath, SaveFormat.ModelSchemaOnly, SerializeOptions.Default); } var replaceMap = new Dictionary <string, string>(); var analyze = upperArgList.IndexOf("-ANALYZE"); if (analyze == -1) { analyze = upperArgList.IndexOf("-A"); } if (analyze > -1) { var rulefile = argList.Skip(analyze + 1).FirstOrDefault(n => !n.StartsWith("-")); var analyzer = new BPA.Analyzer() { Model = h.Model }; BPA.BestPracticeCollection suppliedRules = null; if (!string.IsNullOrEmpty(rulefile)) { if (!File.Exists(rulefile)) { Error("Rulefile not found: {0}", rulefile); return(true); } try { suppliedRules = BPA.BestPracticeCollection.LoadFromJsonFile(rulefile); } catch { Error("Invalid rulefile: {0}", rulefile); return(true); } } cw.WriteLine("Running Best Practice Analyzer..."); cw.WriteLine("================================="); IEnumerable <BPA.AnalyzerResult> bpaResults; if (suppliedRules == null) { bpaResults = analyzer.AnalyzeAll(); } else { bpaResults = analyzer.Analyze(suppliedRules.Concat(analyzer.LocalRules)); } if (!bpaResults.Any()) { cw.WriteLine("No objects in violation of Best Practices."); } foreach (var res in bpaResults) { var text = string.Format("{0} {1} violates rule \"{2}\"", res.Object.GetTypeName(), (res.Object as IDaxObject)?.DaxObjectFullName ?? res.ObjectName, res.RuleName ); if (res.Rule.Severity <= 1) { cw.WriteLine(text); } else if (res.Rule.Severity == 2) { Warning(text); } else if (res.Rule.Severity >= 3) { Error(text); } } cw.WriteLine("================================="); } var deploy = upperArgList.IndexOf("-DEPLOY"); if (deploy == -1) { deploy = upperArgList.IndexOf("-D"); } if (deploy > -1) { var serverName = argList.Skip(deploy + 1).FirstOrDefault(); if (serverName != null && serverName.StartsWith("-")) { serverName = null; } var databaseID = argList.Skip(deploy + 2).FirstOrDefault(); if (databaseID != null && databaseID.StartsWith("-")) { databaseID = null; } var conn = upperArgList.IndexOf("-CONNECTIONS"); if (conn == -1) { conn = upperArgList.IndexOf("-C"); } if (conn > -1) { var replaces = argList.Skip(conn + 1).TakeWhile(s => s[0] != '-').ToList(); if (replaces.Count > 0 && replaces.Count % 2 == 0) { // Placeholder replacing: for (var index = 0; index < replaces.Count; index = index + 2) { replaceMap.Add(replaces[index], replaces[index + 1]); } } } string userName = null; string password = null; var options = DeploymentOptions.StructureOnly; var switches = args.Skip(deploy + 1).Where(arg => arg.StartsWith("-")).Select(arg => arg.ToUpper()).ToList(); if (string.IsNullOrEmpty(serverName) || string.IsNullOrEmpty(databaseID)) { Error("Invalid argument syntax.\n"); OutputUsage(); return(true); } if (switches.Contains("-L") || switches.Contains("-LOGIN")) { var switchPos = upperArgList.IndexOf("-LOGIN"); if (switchPos == -1) { switchPos = upperArgList.IndexOf("-L"); } userName = argList.Skip(switchPos + 1).FirstOrDefault(); if (userName != null && userName.StartsWith("-")) { userName = null; } password = argList.Skip(switchPos + 2).FirstOrDefault(); if (password != null && password.StartsWith("-")) { password = null; } if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password)) { Error("Missing username or password.\n"); OutputUsage(); return(true); } switches.Remove("-L"); switches.Remove("-LOGIN"); } if (switches.Contains("-O") || switches.Contains("-OVERWRITE")) { options.DeployMode = DeploymentMode.CreateOrAlter; switches.Remove("-O"); switches.Remove("-OVERWRITE"); } else { options.DeployMode = DeploymentMode.CreateDatabase; } if (switches.Contains("-P") || switches.Contains("-PARTITIONS")) { options.DeployPartitions = true; switches.Remove("-P"); switches.Remove("-PARTITIONS"); } if (switches.Contains("-C") || switches.Contains("-CONNECTIONS")) { options.DeployConnections = true; switches.Remove("-C"); switches.Remove("-CONNECTIONS"); } if (switches.Contains("-R") || switches.Contains("-ROLES")) { options.DeployRoles = true; switches.Remove("-R"); switches.Remove("-ROLES"); if (switches.Contains("-M") || switches.Contains("-MEMBERS")) { options.DeployRoleMembers = true; switches.Remove("-M"); switches.Remove("-MEMBERS"); } } /*if(switches.Count > 0) * { * Error("Unknown switch {0}\n", switches[0]); * OutputUsage(); * return true; * }*/ try { if (replaceMap.Count > 0) { cw.WriteLine("Switching connection string placeholders..."); foreach (var map in replaceMap) { h.Model.DataSources.SetPlaceholder(map.Key, map.Value); } } cw.WriteLine("Deploying..."); var cs = string.IsNullOrEmpty(userName) ? TabularConnection.GetConnectionString(serverName) : TabularConnection.GetConnectionString(serverName, userName, password); var deploymentResult = TabularDeployer.Deploy(h, cs, databaseID, options); cw.WriteLine("Deployment succeeded."); foreach (var err in deploymentResult.Issues) { Issue(err); } foreach (var err in deploymentResult.Warnings) { Warning(err); } foreach (var err in deploymentResult.Unprocessed) { if (warnOnUnprocessed) { Warning(err); } else { cw.WriteLine(err); } } } catch (Exception ex) { Error("Deployment failed! " + ex.Message); } return(true); } return(true); }