/// <summary> /// Obtiene los nodos de parámetros /// </summary> internal MLNodesCollection GetParametersNodes(NormalizedDictionary <JobParameterModel> parameters) { MLNodesCollection nodesML = new MLNodesCollection(); // Añade los parámetros foreach ((string key, JobParameterModel parameter) in parameters.Enumerate()) { MLNode nodeML = nodesML.Add(TagParameter); // Añade las propiedades nodeML.Attributes.Add(TagKey, key); nodeML.Attributes.Add(TagType, parameter.Type.ToString()); nodeML.Attributes.Add(TagValue, parameter.Value?.ToString()); // Añade las propiedades de las fechas if (parameter.Type == JobParameterModel.ParameterType.DateTime) { nodeML.Attributes.Add(TagComputeMode, parameter.DateMode.ToString()); nodeML.Attributes.Add(TagInterval, parameter.Interval.ToString()); nodeML.Attributes.Add(TagIncrement, parameter.Increment); nodeML.Attributes.Add(TagMode, parameter.Mode.ToString()); } } // Devuelve la colección de nodos return(nodesML); }
/// <summary> /// Ejecuta un script de powershell /// </summary> private async Task ExecuteContentAsync(BlockLogModel block, string content, NormalizedDictionary <object> parameters, ExecuteScriptSentence sentence) { PowerShellManager manager = new PowerShellManager(); // Carga el script en memoria manager.LoadScript(content); // Asigna los parámetros if (!AddParameters(manager, parameters, sentence, out string error)) { Errors.Add(error); } else { // Ejecuta await manager.ExecuteAsync(); // Comprueba los errores if (manager.Errors.Count > 0) { Errors.AddRange(manager.Errors); } else if (manager.OutputItems.Count > 0) { foreach (object output in manager.OutputItems) { block.Info($"{manager.OutputItems.IndexOf(output).ToString()}: {output?.ToString()}"); } } } }
/// <summary> /// Obtiene los parámetros de un archivo /// </summary> private (NormalizedDictionary <object> parameters, string error) GetParameters(string jsonParameters) { NormalizedDictionary <object> parameters = new NormalizedDictionary <object>(); string error = string.Empty; // Carga los parámetros si es necesario if (!string.IsNullOrWhiteSpace(jsonParameters)) { try { System.Data.DataTable table = new LibJsonConversor.JsonToDataTableConversor().ConvertToDataTable(jsonParameters); // Crea la colección de parámetros a partir de la tabla if (table.Rows.Count == 0) { error = "No se ha encontrado ningún parámetro en el archivo"; } else { foreach (System.Data.DataColumn column in table.Columns) { parameters.Add(column.ColumnName, table.Rows[0][column.Ordinal]); } } } catch (Exception exception) { error = $"Error cuando se cargaba el archivo de parámetros. {exception.Message}"; } } // Devuelve el resultado return(parameters, error); }
public void TryGetReturnsNormalized() { var dict = new NormalizedDictionary <int>() { { 1, 1.0 }, { 2, 2.0 }, { 3, 3.0 }, { 4, 4.0 } }; if (dict.TryGetValue(1, out var r1)) { Assert.Equal(1.0 / 10.0, r1); } if (dict.TryGetValue(2, out var r2)) { Assert.Equal(2.0 / 10.0, r2); } if (dict.TryGetValue(3, out var r3)) { Assert.Equal(3.0 / 10.0, r3); } if (dict.TryGetValue(4, out var r4)) { Assert.Equal(4.0 / 10.0, r4); } }
internal DbScriptManager(JobStepModel step, DbAggregatorManager dataProviderManager, NormalizedDictionary <object> parameters, LogManager logger) { Step = step; DataProviderManager = dataProviderManager; Parameters = parameters; Logger = logger; }
/// <summary> /// Copia los archivos /// </summary> private void CopyFiles(string sourcePath, string targetPath, NormalizedDictionary <object> parameters) { // Crea el directorio //? Sí, está dos veces, no sé porqué si se ejecuta dos veces consecutivas este método, la segunda vez no crea el directorio a menos que //? ejecute dos veces la instrucción HelperFiles.MakePath(targetPath); HelperFiles.MakePath(targetPath); // Copia los archivos foreach (string file in System.IO.Directory.EnumerateFiles(sourcePath)) { if (MustCopy(file)) { string targetFile = System.IO.Path.Combine(targetPath, System.IO.Path.GetFileName(file)); // Copia los archivos de Python sin cambios, los de SQL los convierte if (file.EndsWith(".py", StringComparison.CurrentCultureIgnoreCase)) { SaveFileWithoutBom(targetFile, HelperFiles.LoadTextFile(file)); } else if (file.EndsWith(".sql", StringComparison.CurrentCultureIgnoreCase)) { SaveFileWithoutBom(targetFile, TransformSql(file, parameters)); } } } }
/// <summary> /// Carga un parámetro /// </summary> private void LoadParameter(MLNode rootML, NormalizedDictionary <object> parameters) { object value; // Obtiene el valor switch (rootML.Attributes[TagType].Value.GetEnum(ParameterType.Unknown)) { case ParameterType.Numeric: value = rootML.Attributes[TagValue].Value.GetDouble(0); break; case ParameterType.Boolean: value = rootML.Attributes[TagValue].Value.GetBool(); break; case ParameterType.DateTime: value = ConvertDate(rootML); break; default: if (string.IsNullOrWhiteSpace(rootML.Attributes[TagValue].Value)) { value = rootML.Value; } else { value = rootML.Attributes[TagValue].Value; } break; } // Añade el parámetro parameters.Add(rootML.Attributes[TagKey].Value, value); }
/// <summary> /// Depuración de los parámetros del árbol /// </summary> private void Debug(System.Text.StringBuilder builder, string indent, NormalizedDictionary <object> parameters) { // Añade los atributos foreach ((string key, object value) in parameters.Enumerate()) { builder.AppendLine($"{indent} - Parameter: {key}: {value ?? "NULL"}"); } }
/// <summary> /// Pasa los argumentos $xxxx de la cadena SQL a la función getArgument("xxxx") /// </summary> private string TransformArguments(string name, NormalizedDictionary <object> arguments) { if (!arguments.ContainsKey(name)) { return(" getArgument(\"" + name + "\") "); } else { return($"${name.ToLower()}"); } }
/// <summary> /// Procesa las sentencias del script /// </summary> internal async Task <bool> ProcessAsync(BlockLogModel block, List <BaseSentence> program, NormalizedDictionary <object> parameters, CancellationToken cancellationToken) { // Guarda los parámetros de entrada Parameters = parameters; // Ejecuta el programa await ExecuteAsync(block, program, cancellationToken); // Devuelve el valor que indica si todo es correcto return(!HasError); }
/// <summary> /// Crea la lista de parámetros a pasar a la consulta /// </summary> private ParametersDbCollection ConvertParameters(IDbProvider provider, NormalizedDictionary <object> parameters) { ParametersDbCollection parametersDb = new ParametersDbCollection(); // Convierte los parámetros foreach ((string key, object value) in parameters.Enumerate()) { parametersDb.Add($"{provider.SqlHelper.ParameterPrefix}{key}", value); } // Devuelve la colección de parámetros para la base de datos return(parametersDb); }
//? Está comentado porque Spark SQL no admite las cadenas ODBC con marcadores de parámetros, por eso se utiliza la rutina anterior ///// <summary> ///// Ejecuta una serie de comandos utilizando parámetros de base de datos ///// </summary> //private int ExecuteCommands(List<string> commands, NormalizedDictionary<object> parameters, TimeSpan timeOut) //{ // int scriptsExecuted = 0; // SparkSqlTools sqlTools = new SparkSqlTools(); // ParametersDbCollection parametersDb = ConvertParameters(parameters); // // Ejecuta los comandos // using (SparkProvider provider = new SparkProvider(new SparkConnectionString(Manager.Connection.ConnectionString))) // { // // Abre la conexión // provider.Open(); // // Ejecuta las consultas // foreach (string command in commands) // { // (string sqlNormalized, ParametersDbCollection parameterNormalizedDb) = sqlTools.NormalizeSql(command, parametersDb, "$"); // // Ejecuta la cadena SQL // provider.Execute(sqlNormalized, parameterNormalizedDb, System.Data.CommandType.Text, timeOut); // // Indica que se ha ejecutado una sentencia // scriptsExecuted++; // } // } // // Devuelve el número de comandos ejecutados // return scriptsExecuted; //} /// <summary> /// Crea la lista de parámetros a pasar a la consulta /// </summary> private ParametersDbCollection ConvertParameters(NormalizedDictionary <object> parameters) { ParametersDbCollection parametersDb = new ParametersDbCollection(); // Convierte los parámetros foreach ((string key, object value) in parameters.Enumerate()) { parametersDb.Add("$" + key, value); } // Devuelve la colección de parámetros para la base de datos return(parametersDb); }
/// <summary> /// Obtiene los parámetros de una lista de parámetros de trabajo /// </summary> private NormalizedDictionary <object> GetParameters(NormalizedDictionary <JobParameterModel> parameters) { NormalizedDictionary <object> result = new NormalizedDictionary <object>(); // Convierte los parámetros foreach ((string key, JobParameterModel parameter) in parameters.Enumerate()) { result.Add(key, parameter.Value); } // Devuelve el diccionario de parámetros return(result); }
/// <summary> /// Reemplaza las variables que aparezcan entre {{ }} /// </summary> private string ReplaceVariables(string sql, NormalizedDictionary <object> parameters) { // Reemplaza las variables foreach ((string key, object value) in parameters.Enumerate()) { sql = sql.ReplaceWithStringComparison("{{" + key + "}}", value.ToString()); } // Reemplaza los valores de escape (\{\{ y \}\} sql = sql.ReplaceWithStringComparison("\\{\\{", "{{"); sql = sql.ReplaceWithStringComparison("\\}\\}", "}}"); // Devuelve la cadena convertida return(sql); }
/// <summary> /// Reemplaza las constantes /// </summary> private string ReplaceConstants(string content, NormalizedDictionary <object> parameters) { // Reemplaza las constantes foreach ((string key, object value) in parameters.Enumerate()) { string parameter = (value ?? "").ToString(); // Reemplaza el contenido content = content.ReplaceWithStringComparison("{{" + key + "}}", parameter); } // Devuelve el contenido return(content); }
/// <summary> /// Obtiene las conexiones asociadas a un trabajo: primero las de los pasos padre porque las de los hijos son más restrictivas /// </summary> private NormalizedDictionary <Models.CloudConnection> GetConnections(JobStepModel job) { NormalizedDictionary <Models.CloudConnection> connections = new NormalizedDictionary <Models.CloudConnection>(); // Añade las conexiones de los pasos padre if (job.Parent != null) { connections.AddRange(GetConnections(job.Parent)); } // Añade las conexiones del paso connections.AddRange(GetConnections(job.Context)); // Devuelve la colección de conexiones return(connections); }
/// <summary> /// Obtiene los parámetros de un paso: primero obtiene los parámetros de sus ancestros porque se supone que cuánto más /// abajo, más específico /// </summary> private NormalizedDictionary <object> GetParameters(JobStepModel step) { NormalizedDictionary <object> parameters = new NormalizedDictionary <object>(); // Obtiene la colección de parámetros del padre if (step.Parent != null) { parameters.AddRange(GetParameters(step.Parent)); } // y le añade los parámetros de este paso parameters.AddRange(GetParameters(step.Context.Parameters)); // Devuelve la colección de parámetros return(parameters); }
/// <summary> /// Obtiene los parámetros del paso /// </summary> private NormalizedDictionary <object> GetParameters(List <JobContextModel> contexts, JobStepModel step) { NormalizedDictionary <object> parameters = new NormalizedDictionary <object>(); // Añade los parámetros de los contextos foreach (JobContextModel context in contexts) { parameters.AddRange(GetParameters(context.Parameters)); } // Añade al diccionario los parámetros del script (desde el padre hacia abajo: los más internos son los que prevalecen // porque son más específicos que los externos) parameters.AddRange(GetParameters(step)); // Devuelve el diccionario de parámetros return(parameters); }
/// <summary> /// Interpreta una cadena SQL separando los comentarios /// </summary> internal List <ScriptSqlPartModel> Parse(string sql, NormalizedDictionary <object> variables) { List <ScriptSqlPartModel> sqlParts = Tokenize(sql); // Reemplaza las variables foreach (ScriptSqlPartModel sqlPart in sqlParts) { if (sqlPart.Type == ScriptSqlPartModel.PartType.Sql) { sqlPart.Content = ReplaceVariables(sqlPart.Content, variables); } } // Devuelve las secciones de la cadena SQL return(sqlParts); }
public void ItemReturnsNormalized() { var dict = new NormalizedDictionary <int>() { { 1, 1.0 }, { 2, 2.0 }, { 3, 3.0 }, { 4, 4.0 } }; Assert.Equal(1.0 / 10.0, dict[1]); Assert.Equal(2.0 / 10.0, dict[2]); Assert.Equal(3.0 / 10.0, dict[3]); Assert.Equal(4.0 / 10.0, dict[4]); }
/// <summary> /// Carga una colección de parámetros /// </summary> internal NormalizedDictionary <JobParameterModel> LoadParameters(MLNode rootML) { NormalizedDictionary <JobParameterModel> parameters = new NormalizedDictionary <JobParameterModel>(); // Carga los parámetros foreach (MLNode nodeML in rootML.Nodes) { if (nodeML.Name == TagParameter) { JobParameterModel parameter = LoadParameter(nodeML); parameters.Add(parameter.Key, parameter); } } // Devuelve la colección de parámetros return(parameters); }
/// <summary> /// Obtiene las conexiones de un contexto /// </summary> private NormalizedDictionary <DataBaseConnectionModel> GetConnections(JobProjectModel project, JobContextModel context) { NormalizedDictionary <DataBaseConnectionModel> connections = new NormalizedDictionary <DataBaseConnectionModel>(); // Obtiene las conexiones del árbol foreach (LibDataStructures.Trees.TreeNodeModel node in context.Tree.Nodes) { if (node.Id.EqualsIgnoreCase("Connection")) { DataBaseConnectionModel connection = GetConnection(project, node); connections.Add(connection.GlobalId, connection); } } // Devuelve la lista de conexiones return(connections); }
/// <summary> /// Procesa un trabajo /// </summary> public async Task <bool> ProcessAsync(List <JobContextModel> contexts, JobStepModel step, CancellationToken cancellationToken) { NormalizedDictionary <object> parameters = GetParameters(contexts, step); bool processed = false; // Procesa el paso try { processed = await ProcessStepAsync(contexts, step, parameters, cancellationToken); } catch (Exception exception) { Errors.Add($"Error when execute step '{step.Name}'. {exception}"); } // Devuelve el valor que indica si se ha procesado correctamente return(processed); }
/// <summary> /// Obtiene los parámetros combinados del paso y el trabajo /// </summary> public NormalizedDictionary <object> GetCombinedParameters() { NormalizedDictionary <object> parameters = new NormalizedDictionary <object>(); // Asigna los parámetros del trabajo foreach ((string key, object value) in Job.Parameters.Enumerate()) { parameters.Add(key, value); } // Asigna los parámetros del paso foreach ((string key, object value) in Parameters.Enumerate()) { parameters.Add(key, value); } // Devuelve el diccionario de parámetros return(parameters); }
/// <summary> /// Obtiene las conexiones de un contexto /// </summary> private NormalizedDictionary <Models.CloudConnection> GetConnections(JobContextModel context) { NormalizedDictionary <Models.CloudConnection> connections = new NormalizedDictionary <Models.CloudConnection>(); // Obtiene las conexiones del árbol foreach (LibDataStructures.Trees.TreeNodeModel node in context.Tree.Nodes) { if (node.Id.EqualsIgnoreCase("Cloud")) { Models.CloudConnection configuration = GetConnection(node); connections.Add(configuration.Key, configuration); } } // Devuelve la lista de conexiones return(connections); }
/// <summary> /// Genera los archivos /// </summary> public async Task <bool> GenerateAsync(CancellationToken cancellationToken) { IDbProvider provider = Manager.DbScriptsManager.GetDbProvider(Options.Connection); // Limpia los errores Errors.Clear(); // Genera los archivos if (provider == null) { Errors.Add($"Cant find provider for connection '{Options.Connection.Name}'"); } else { EtlFilesGenerator generator = new EtlFilesGenerator(Options.Connection, provider, Options.OutputPath); NormalizedDictionary <List <ConnectionTableModel> > schemaTables = GetSchemaTablesSelected(); int index = 1; // Genera el archivo de creación de la base de datos generator.WriteFileCreateConnection(Options.DataBaseValidateVariable, Options.MountPathVariable, "00. Create database.sql"); // Carga el esquema await Manager.DbScriptsManager.LoadSchemaAsync(Options.Connection, cancellationToken); // Prepara los archivos de validación de tablas foreach ((string schema, List <ConnectionTableModel> tables) in schemaTables.Enumerate()) { if (!cancellationToken.IsCancellationRequested) { // Prepara los scripts de validación PrepareFilesValidation(generator, schema, tables, true, index); PrepareFilesValidation(generator, schema, tables, false, index + 1); // Prepara el archivo de validación de QlikView si es necesario if (Options.GenerateQvs) { PrepareFileValidationQvs(generator, schema, tables); } // Incrementa el índice index += 2; } } // Prepara el archivo JSON de parámetros PrepareParametersFile(generator); } // Devuelve el valor que indica si la generación ha sido correcta return(Errors.Count == 0); }
/// <summary> /// Obtiene un diccionario con los esquemas y tablas seleccionados /// </summary> private NormalizedDictionary <List <ConnectionTableModel> > GetSchemaTablesSelected() { NormalizedDictionary <List <ConnectionTableModel> > tables = new NormalizedDictionary <List <ConnectionTableModel> >(); // Añade los esquemas a la lista foreach (ConnectionTableModel table in Options.Tables) { // Si no existe el esquema en el diccionario, lo añade if (!tables.ContainsKey(table.Schema)) { tables.Add(table.Schema, new List <ConnectionTableModel>()); } // Añade la tabla a la lista tables[table.Schema].Add(table); } // Devuelve el diccionario de tablas por esquema return(tables); }
/// <summary> /// Obtiene e inicializa el controlador de proveedores de datos /// </summary> private DbAggregatorManager GetProviderManager(List <JobContextModel> contexts, JobStepModel job) { DbAggregatorManager providersManager = new DbAggregatorManager(); NormalizedDictionary <DataBaseConnectionModel> connections = GetConnections(contexts, job); // Asign las conexiones al proveedor foreach ((string key, DataBaseConnectionModel connection) in connections.Enumerate()) { DbAggregator.Models.ConnectionModel dbConnection = new DbAggregator.Models.ConnectionModel(key, connection.Type.ToString()); // Añade los parámetros dbConnection.Parameters.AddRange(connection.Parameters); // Añade la conexión providersManager.AddConnection(dbConnection); } // Devuelve el agregado return(providersManager); }
/// <summary> /// Obtiene las conexiones del contexto y del trabajo /// </summary> private NormalizedDictionary <Models.CloudConnection> GetConnections(List <JobContextModel> contexts, JobStepModel job) { NormalizedDictionary <Models.CloudConnection> connections = new NormalizedDictionary <Models.CloudConnection>(); // Obtiene los proveedores de los contextos globales foreach (JobContextModel context in contexts) { if (!string.IsNullOrWhiteSpace(context.ProcessorKey) && context.ProcessorKey.Equals(Key, StringComparison.CurrentCultureIgnoreCase)) { connections.AddRange(GetConnections(context)); } } // Obtiene los proveedores del contexto del trabajo connections.AddRange(GetConnections(job)); // Devuelve las conexiones return(connections); }
/// <summary> /// Añade los parámetros al powershell que se va a ejecutar /// </summary> private bool AddParameters(PowerShellManager manager, NormalizedDictionary <object> parameters, ExecuteScriptSentence sentence, out string error) { // Inicializa los argumentos de salida error = string.Empty; // Añade los parámetros foreach ((string key, string value) in sentence.Mappings.Enumerate()) { if (parameters.ContainsKey(key)) { manager.AddParameter(value, parameters[key]); } } // Añade los directorios foreach ((string key, string value) in sentence.Paths.Enumerate()) { manager.AddParameter(key, Step.Project.GetFullFileName(value)); } // Devuelve el valor que indica si ha habido algún error return(string.IsNullOrEmpty(error)); }