/// <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);
        }
Beispiel #2
0
        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);
        }