diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Diagnostic/ReaderDiagnosticResult.cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Diagnostic/ReaderDiagnosticResult.cs index e8512ed50..d2b57162d 100644 --- a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Diagnostic/ReaderDiagnosticResult.cs +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Diagnostic/ReaderDiagnosticResult.cs @@ -29,6 +29,24 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader /// public object Data { get; set; } + public static ReaderDiagnosticResult SuccessResult(string message = "OK") + { + return new ReaderDiagnosticResult + { + Success = true, + Message = message + }; + } + + public static ReaderDiagnosticResult Failure(string message) + { + return new ReaderDiagnosticResult + { + Success = false, + Message = message + }; + } + public ReaderDiagnosticResult() { Diagnostics = new List(); @@ -55,17 +73,4 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader return sb.ToString(); } } - public class CsvSearchResult - { - public bool Found { get; set; } - public string FilePath { get; set; } - public string HeaderLine { get; set; } - public string MatchedLine { get; set; } - public Dictionary Values { get; set; } - - public CsvSearchResult() - { - Values = new Dictionary(); - } - } } \ No newline at end of file diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Interfaces/DataQuery.cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Interfaces/DataQuery.cs index 7f7f56a2b..76d984c74 100644 --- a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Interfaces/DataQuery.cs +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Interfaces/DataQuery.cs @@ -1,16 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; -namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces +namespace TBF.Rig.Input.DataStorage.UniDataStorageReader { + /// + /// Represents query input for data storage readers. + /// Each value is used to execute the same query template once. + /// A single-item list represents a single query. + /// public class DataQuery { /// - /// + /// Parameter values used for repeated execution of the same query template. /// - public string QueryParam { get; set; } + public List QueryParams { get; } = new List(); } -} +} \ No newline at end of file diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Interfaces/IDataStorageReader.cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Interfaces/IDataStorageReader.cs index 002e45d08..373d086c4 100644 --- a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Interfaces/IDataStorageReader.cs +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Interfaces/IDataStorageReader.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces; namespace TBF.Rig.Input.DataStorage.UniDataStorageReader { diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Reader.cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Reader.cs index 75e079991..657780198 100644 --- a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Reader.cs +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Reader.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using TBF.Rig.Generic; -using TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces; using TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers; using TBF.Rig.Scales.MettlerToledo; using static TBF.Rig.Input.DataStorage.UniDataStorageReader.ReaderCfg; diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/CsvReader .cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/CsvReader .cs index b1b116f1f..1c100837a 100644 --- a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/CsvReader .cs +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/CsvReader .cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces; using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching; namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers @@ -24,6 +23,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers /// /// Reads data from CSV and returns matched row data. + /// Executes the same query template for each value in DataQuery.QueryParams. /// public object GetData(DataQuery query) { @@ -50,7 +50,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers } /// - /// Tests whether the configured query column exists in the CSV source. + /// Tests whether the configured query columns exist in the CSV source. /// public ReaderDiagnosticResult TestQuery(bool enableDiagnostics) { @@ -148,6 +148,9 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers return result; } + /// + /// Executes the configured query for all provided parameter values. + /// private ReaderDiagnosticResult ExecuteQuery(DataQuery query, bool enableDiagnostics) { ReaderDiagnosticResult result = new ReaderDiagnosticResult(); @@ -159,8 +162,8 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers if (query == null) throw new InvalidOperationException("DataQuery is null."); - if (string.IsNullOrWhiteSpace(query.QueryParam)) - throw new InvalidOperationException("DataQuery.QueryParam is empty."); + if (query.QueryParams == null || query.QueryParams.Count == 0) + throw new InvalidOperationException("DataQuery.QueryParams is empty."); if (loadedLines == null || loadedLines.Length == 0) throw new InvalidOperationException("CSV source is not connected."); @@ -173,50 +176,75 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers Log(result, enableDiagnostics, "QueryTemplate parsed successfully."); Log(result, enableDiagnostics, "Select column: " + definition.SelectColumn); Log(result, enableDiagnostics, "Where column: " + definition.WhereColumn); - Log(result, enableDiagnostics, "QueryParam: " + query.QueryParam); int selectIndex = ResolveColumnIndex(loadedHeaders, definition.SelectColumn); int whereIndex = ResolveColumnIndex(loadedHeaders, definition.WhereColumn); Log(result, enableDiagnostics, "Resolved select column index: " + selectIndex); Log(result, enableDiagnostics, "Resolved where column index: " + whereIndex); + Log(result, enableDiagnostics, "Query parameter count: " + query.QueryParams.Count); - for (int i = 1; i < loadedLines.Length; i++) + List matchedValues = new List(); + int matchCount = 0; + + for (int paramIndex = 0; paramIndex < query.QueryParams.Count; paramIndex++) { - if (string.IsNullOrWhiteSpace(loadedLines[i])) - continue; + string queryValue = (query.QueryParams[paramIndex] ?? string.Empty).Trim(); - string[] values = SplitCsvLine(loadedLines[i]); + Log(result, enableDiagnostics, string.Format("=== Query item {0} ===", paramIndex + 1)); + Log(result, enableDiagnostics, "QueryParam: " + queryValue); - if (whereIndex >= values.Length) - continue; + bool found = false; - string currentValue = (values[whereIndex] ?? string.Empty).Trim(); - - if (string.Equals( - currentValue, - query.QueryParam.Trim(), - StringComparison.OrdinalIgnoreCase)) + for (int lineIndex = 1; lineIndex < loadedLines.Length; lineIndex++) { - string returnValue = selectIndex < values.Length - ? values[selectIndex] - : string.Empty; + if (string.IsNullOrWhiteSpace(loadedLines[lineIndex])) + continue; - Log(result, enableDiagnostics, "Match found at line index: " + i); - Log(result, enableDiagnostics, "Returned value: " + returnValue); + string[] values = SplitCsvLine(loadedLines[lineIndex]); - result.Success = true; - result.Message = "Value found."; - result.Data = returnValue; - return result; + if (whereIndex >= values.Length) + continue; + + string currentValue = (values[whereIndex] ?? string.Empty).Trim(); + + if (string.Equals(currentValue, queryValue, StringComparison.OrdinalIgnoreCase)) + { + string returnValue = selectIndex < values.Length + ? values[selectIndex] + : string.Empty; + + Log(result, enableDiagnostics, "Match found at line index: " + lineIndex); + Log(result, enableDiagnostics, "Returned value: " + returnValue); + + matchedValues.Add(returnValue); + matchCount++; + found = true; + break; + } + } + + if (!found) + { + Log(result, enableDiagnostics, "No matching row found."); } } - Log(result, enableDiagnostics, "No matching row found."); + if (query.QueryParams.Count == 1) + { + result.Data = matchedValues.Count > 0 ? (object)matchedValues[0] : null; + result.Message = matchedValues.Count > 0 ? "Value found." : "No match found."; + } + else + { + result.Data = matchedValues; + result.Message = string.Format( + "Batch query finished. Matches found: {0} of {1}.", + matchCount, + query.QueryParams.Count); + } result.Success = true; - result.Message = "No match found."; - result.Data = null; } catch (Exception ex) { @@ -250,7 +278,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers } /// - /// Splits CSV line by semicolon. + /// Splits CSV line by common separators. /// Simple implementation without quoted-separator support. /// private string[] SplitCsvLine(string line) @@ -267,7 +295,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers if (line.Contains("\t")) return line.Split('\t'); - return new string[] { line }; + return new[] { line }; } /// diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/DatabaseReader .cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/DatabaseReader .cs index f39e39757..57fdaf946 100644 --- a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/DatabaseReader .cs +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/DatabaseReader .cs @@ -1,38 +1,245 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces; +using System.Data; +using System.Data.SqlClient; +using System.Reflection; +using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching; +using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching.Database; namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers { + /// + /// Reader implementation for SQL Server based data source. + /// DataSource = SQL Server connection string + /// QueryTemplate = SQL query containing QUERYPARAM placeholder + /// public class DatabaseReader : IDataStorageReader { private readonly ReaderCfg cfg; + public ReaderDiagnosticResult TestSource(bool enableDiagnostics) + { + ReaderDiagnosticResult result = new ReaderDiagnosticResult(); + + try + { + if (string.IsNullOrWhiteSpace(cfg.DataSource)) + { + result.Success = false; + result.Message = "Data source is empty."; + return result; + } + + if (enableDiagnostics) + result.Diagnostics.Add("Opening SQL connection..."); + + using (SqlConnection connection = new SqlConnection(cfg.DataSource)) + { + connection.Open(); + + if (enableDiagnostics) + result.Diagnostics.Add("Connection opened successfully."); + + using (SqlCommand command = new SqlCommand("SELECT 1", connection)) + { + object val = command.ExecuteScalar(); + + if (enableDiagnostics) + result.Diagnostics.Add("Test query executed. Result=" + val); + } + } + + result.Success = true; + result.Message = "Connection to SQL Server OK."; + return result; + } + catch (Exception ex) + { + result.Success = false; + result.Message = "Failed to connect to SQL Server."; + + if (enableDiagnostics) + result.Diagnostics.Add(ex.ToString()); + + return result; + } + } + + public ReaderDiagnosticResult TestQuery(bool enableDiagnostics) + { + ReaderDiagnosticResult result = new ReaderDiagnosticResult(); + + try + { + if (string.IsNullOrWhiteSpace(cfg.QueryTemplate)) + { + result.Success = false; + result.Message = "Query template is empty."; + return result; + } + + string sql = PrepareSqlText(cfg.QueryTemplate); + + if (enableDiagnostics) + { + result.Diagnostics.Add("Original template:"); + result.Diagnostics.Add(cfg.QueryTemplate); + + result.Diagnostics.Add("Prepared SQL:"); + result.Diagnostics.Add(sql); + } + + using (SqlConnection connection = new SqlConnection(cfg.DataSource)) + using (SqlCommand command = new SqlCommand(sql, connection)) + { + // dummy parameter + command.Parameters.AddWithValue("@value", "TEST"); + + if (enableDiagnostics) + result.Diagnostics.Add("Parameter @value = TEST"); + + connection.Open(); + + object val = command.ExecuteScalar(); + + if (enableDiagnostics) + result.Diagnostics.Add("Query executed successfully."); + + result.Data = val; // môže byť null → OK + } + + result.Success = true; + result.Message = "Query executed successfully."; + return result; + } + catch (Exception ex) + { + result.Success = false; + result.Message = "Query execution failed."; + + if (enableDiagnostics) + result.Diagnostics.Add(ex.ToString()); + + return result; + } + } + public DatabaseReader(ReaderCfg cfg) { this.cfg = cfg ?? throw new ArgumentNullException(nameof(cfg)); } + /// + /// Reads data from SQL Server and returns matched data. + /// If query returns 1 column, scalar value is returned. + /// If query returns multiple columns, Dictionary<string, object> is returned. + /// public object GetData(DataQuery query) + { + if (query == null) + throw new ArgumentNullException(nameof(query)); + + ReaderDiagnosticResult connectResult = ConnectToSource(true); + if (!connectResult.Success) + throw new InvalidOperationException(connectResult.Message); + + string sqlText = PrepareSqlText(cfg.QueryTemplate); + object queryValue = ExtractQueryValue(query); + + using (SqlConnection connection = new SqlConnection(cfg.DataSource)) + using (SqlCommand command = new SqlCommand(sqlText, connection)) + { + AddQueryParameters(command, queryValue); + + connection.Open(); + + using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow)) + { + DatabaseSearchResult result = new DatabaseSearchResult(); + result.Query = sqlText; + + if (!reader.Read()) + { + result.Found = false; + return result; + } + + result.Found = true; + + for (int i = 0; i < reader.FieldCount; i++) + { + object value = reader.GetValue(i); + result.Values[reader.GetName(i)] = value == DBNull.Value ? null : value; + } + + return result; + } + } + } + + /// + /// Validates database connectivity and basic query readiness. + /// + public ReaderDiagnosticResult ConnectToSource(bool validateExistence) { if (string.IsNullOrWhiteSpace(cfg.DataSource)) - throw new InvalidOperationException("Database data source is empty."); + return ReaderDiagnosticResult.Failure("Data source must not be empty."); - // TODO: DB connection + SQL query by searchOrder - return null; + if (string.IsNullOrWhiteSpace(cfg.QueryTemplate)) + return ReaderDiagnosticResult.Failure("Query template must not be empty."); + + try + { + using (SqlConnection connection = new SqlConnection(cfg.DataSource)) + { + connection.Open(); + + if (validateExistence) + { + using (SqlCommand command = new SqlCommand("SELECT 1", connection)) + { + command.ExecuteScalar(); + } + } + } + + return ReaderDiagnosticResult.SuccessResult(); + } + catch (Exception ex) + { + return ReaderDiagnosticResult.Failure( + string.Format("Failed to connect to SQL Server data source. {0}", ex.Message)); + } } - public ReaderDiagnosticResult TestQuery(bool enableDiagnostics) + private static string PrepareSqlText(string queryTemplate) { - throw new NotImplementedException(); + if (string.IsNullOrWhiteSpace(queryTemplate)) + throw new ArgumentException("Query template must not be empty.", nameof(queryTemplate)); + + if (!queryTemplate.Contains("QUERYPARAM")) + throw new InvalidOperationException("Query template must contain QUERYPARAM placeholder."); + + return queryTemplate.Replace("QUERYPARAM", "@value"); } - public ReaderDiagnosticResult TestSource(bool enableDiagnostics) + private static void AddQueryParameters(SqlCommand command, object queryValue) { - throw new NotImplementedException(); + command.Parameters.Clear(); + + SqlParameter parameter = command.Parameters.Add("@value", SqlDbType.Variant); + parameter.Value = queryValue ?? DBNull.Value; + } + + private static object ExtractQueryValue(DataQuery query) + { + if (query == null) + throw new ArgumentNullException(nameof(query)); + + if (query.QueryParams == null || query.QueryParams.Count == 0) + throw new InvalidOperationException("DataQuery does not contain any query parameter."); + + return query.QueryParams[0]; } } -} +} \ No newline at end of file diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/JsonReader .cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/JsonReader .cs index d11b3327c..10d327395 100644 --- a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/JsonReader .cs +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/JsonReader .cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; -using TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces; namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers { diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/RestApiReader .cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/RestApiReader .cs index 75f348195..70bba9b38 100644 --- a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/RestApiReader .cs +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Readers/RestApiReader .cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces; namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers { diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Searching/Csv/CsvSearchResult.cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Searching/Csv/CsvSearchResult.cs new file mode 100644 index 000000000..534a0560b --- /dev/null +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Searching/Csv/CsvSearchResult.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching.Csv +{ + public class CsvSearchResult + { + public bool Found { get; set; } + public string FilePath { get; set; } + public string HeaderLine { get; set; } + public string MatchedLine { get; set; } + public Dictionary Values { get; set; } + + public CsvSearchResult() + { + Values = new Dictionary(); + } + } +} diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/Searching/Database/DatabaseSearchResult.cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Searching/Database/DatabaseSearchResult.cs new file mode 100644 index 000000000..69bc967e8 --- /dev/null +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/Searching/Database/DatabaseSearchResult.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching.Database +{ + public class DatabaseSearchResult + { + public bool Found { get; set; } + public string Query { get; set; } + public Dictionary Values { get; set; } + + public DatabaseSearchResult() + { + Values = new Dictionary(); + } + } +} diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/UI/ReaderCfgCtrl.cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/UI/ReaderCfgCtrl.cs index cd3b8f9ce..24ba19efb 100644 --- a/TBF/Rig/Input/DataStorage/UniDataStorageReader/UI/ReaderCfgCtrl.cs +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/UI/ReaderCfgCtrl.cs @@ -1,18 +1,26 @@ using Common; using System; +using System.Collections.Generic; using System.Text; using TBF.Rig.Generic; -using TBF.Rig.Input.DataStorage.UniDataStorageReader.Interfaces; using TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers; +using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching.Database; using static TBF.Rig.Input.DataStorage.UniDataStorageReader.ReaderCfg; namespace TBF.Rig.Input.DataStorage.UniDataStorageReader { + /// + /// UI configuration control for UniDataStorageReader. + /// Provides testing capabilities for data source and query execution. + /// public partial class ReaderCfgCtrl : Configs.ConfigCtrlUtils, IComponentCfgCtrl { + private readonly List batchQueryParamValues = new List(); + public bool ShowMore { get { return false; } } - ReaderCfg config; + private ReaderCfg config; + public IComponentCfg Config { get { return config as IComponentCfg; } @@ -29,6 +37,8 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader connectToDataSourceButton.Click += testByDataSourceButton_Click; getDataByQueryParamAndTemplateButton.Click += getDataByQueryParamAndTemplateButton_Click; + buttonAddParam.Click += buttonAddParam_Click; + buttonRemoveParam.Click += buttonRemoveParam_Click; } private void ReaderCfgCtrl_Load(object sender, EventArgs e) @@ -41,7 +51,10 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader { } - void Redraw() + /// + /// Refreshes UI with current configuration values. + /// + private void Redraw() { if (config == null) return; @@ -63,8 +76,12 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader } dataStorageTypeComboBox.Text = config.DataStorageType; + RefreshQueryParamsListBox(); } + /// + /// Enables editing controls. + /// public void Unlock() { nameTextBox.Enabled = true; @@ -77,6 +94,11 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader textBox2.Enabled = true; textBox2.ReadOnly = true; + + queryParamValueTextBox.Enabled = true; + listBoxQueryParams.Enabled = true; + buttonAddParam.Enabled = true; + buttonRemoveParam.Enabled = true; } public CfgUpdateFlags VerifyCfg(ref string message) @@ -84,6 +106,9 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader return CfgUpdateFlags.None; } + /// + /// Applies changes from UI into configuration. + /// public CfgUpdateFlags UpdateCfg() { CfgUpdateFlags flags = CfgUpdateFlags.None; @@ -104,7 +129,8 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader } /// - /// Builds temporary configuration from current UI values. + /// Builds temporary configuration from UI. + /// Used by test actions so saved configuration is not required. /// private ReaderCfg BuildTemporaryConfigFromUi() { @@ -120,7 +146,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader } /// - /// Creates appropriate storage reader based on selected storage type. + /// Creates appropriate reader implementation based on selected storage type. /// private IDataStorageReader CreateReader(ReaderCfg cfg) { @@ -169,6 +195,107 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader } } + /// + /// Executes query using values from the batch list only. + /// + private void getDataByQueryParamAndTemplateButton_Click(object sender, EventArgs e) + { + textBox2.Clear(); + + try + { + if (batchQueryParamValues.Count == 0) + throw new InvalidOperationException("At least one batch test value must be provided."); + + ReaderCfg tmpCfg = BuildTemporaryConfigFromUi(); + IDataStorageReader reader = CreateReader(tmpCfg); + + StringBuilder sb = new StringBuilder(); + sb.Append(BuildDiagnosticHeader(tmpCfg, "Query test")); + + foreach (var value in batchQueryParamValues) + { + DataQuery query = new DataQuery(); + query.QueryParams.Add(value); + + object queryResult = reader.GetData(query); + + sb.AppendLine("--- Param: " + value + " ---"); + + if (queryResult is DatabaseSearchResult dbResult) + { + sb.AppendLine("Found: " + dbResult.Found); + sb.AppendLine("Query: " + dbResult.Query); + + if (dbResult.Values != null && dbResult.Values.Count > 0) + { + sb.AppendLine("Returned values:"); + + foreach (var kvp in dbResult.Values) + sb.AppendLine(kvp.Key + " = " + (kvp.Value ?? "")); + } + } + else if (queryResult is ReaderDiagnosticResult diagResult) + { + sb.AppendLine(diagResult.ToDisplayDiag()); + } + else + { + sb.AppendLine(queryResult != null ? queryResult.ToString() : ""); + } + + sb.AppendLine(); + } + + textBox2.Text = sb.ToString(); + } + catch (Exception ex) + { + textBox2.Text = BuildExceptionText("GetData test failed", ex); + } + } + + /// + /// Adds a single batch test value into the list. + /// + private void buttonAddParam_Click(object sender, EventArgs e) + { + string value = queryParamValueTextBox.Text?.Trim(); + + if (string.IsNullOrWhiteSpace(value)) + return; + + batchQueryParamValues.Add(value); + queryParamValueTextBox.Clear(); + RefreshQueryParamsListBox(); + } + + /// + /// Removes the selected batch test value from the list. + /// + private void buttonRemoveParam_Click(object sender, EventArgs e) + { + int index = listBoxQueryParams.SelectedIndex; + if (index < 0 || index >= batchQueryParamValues.Count) + return; + + batchQueryParamValues.RemoveAt(index); + RefreshQueryParamsListBox(); + } + + /// + /// Refreshes ListBox content and shows line numbering. + /// + private void RefreshQueryParamsListBox() + { + listBoxQueryParams.Items.Clear(); + + for (int i = 0; i < batchQueryParamValues.Count; i++) + { + listBoxQueryParams.Items.Add(string.Format("{0}. {1}", i + 1, batchQueryParamValues[i])); + } + } + /// /// Builds common header for diagnostic output. /// @@ -216,7 +343,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader } /// - /// Converts internal storage-type identifier to user-friendly name. + /// Converts internal storage type identifier to user-friendly name. /// private string StorageTypeToDisplayName(string storageType) { @@ -247,79 +374,5 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader return Safe(storageType); } } - - private void getDataByQueryParamAndTemplateButton_Click(object sender, EventArgs e) - { - textBox2.Clear(); - - try - { - /* //comment, because i need only using of GetData() as in real using - // 1. config z UI - ReaderCfg tmpCfg = BuildTemporaryConfigFromUi(); - - // 2. query z UI - DataQuery query = BuildDataQueryFromUi(); - - // 3. reader - IDataStorageReader reader = CreateReader(tmpCfg); - - StringBuilder sb = new StringBuilder(); - - sb.AppendLine("=== GetData test ==="); - sb.AppendLine("Storage type: " + StorageTypeToDisplayName(tmpCfg.DataStorageType)); - sb.AppendLine("Data source: " + Safe(tmpCfg.DataSource)); - sb.AppendLine(); - - // 🔹 display query - sb.AppendLine("Query:"); - sb.AppendLine("QueryParam: " + Safe(query.QueryParam)); - sb.AppendLine(); - - // 4. test order - sb.AppendLine("=== Query validation ==="); - - ReaderDiagnosticResult queryResult = reader.TestQuery(true); - - sb.AppendLine(queryResult.ToDisplayDiag()); - sb.AppendLine(); - - if (!queryResult.Success) - { - sb.AppendLine("GetData skipped due to query validation failure."); - textBox2.Text = sb.ToString(); - return; - } - - // 5. real GetData - sb.AppendLine("=== Executing GetData ==="); - - object value = reader.GetData(query); - - sb.AppendLine(); - sb.AppendLine("Result:"); - - if (value == null) - { - sb.AppendLine(""); - } - else - { - sb.AppendLine(value.ToString()); - } - - textBox2.Text = sb.ToString();*/ - - //real example of using - IDataStorageReader reader = CreateReader(this.config); - DataQuery query = new DataQuery(); - query.QueryParam = queryParamTextBox.Text; - textBox2.Text = ((ReaderDiagnosticResult)reader.GetData(query)).ToDisplayDiag(); - } - catch (Exception ex) - { - textBox2.Text = BuildExceptionText("GetData test failed", ex); - } - } } } \ No newline at end of file diff --git a/TBF/Rig/Input/DataStorage/UniDataStorageReader/UI/ReaderCfgCtrl.designer.cs b/TBF/Rig/Input/DataStorage/UniDataStorageReader/UI/ReaderCfgCtrl.designer.cs index b3af52ef4..11de54773 100644 --- a/TBF/Rig/Input/DataStorage/UniDataStorageReader/UI/ReaderCfgCtrl.designer.cs +++ b/TBF/Rig/Input/DataStorage/UniDataStorageReader/UI/ReaderCfgCtrl.designer.cs @@ -3,34 +3,35 @@ /// namespace TBF.Rig.Input.DataStorage.UniDataStorageReader { - partial class ReaderCfgCtrl - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; + partial class ReaderCfgCtrl + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } - #region Component Designer generated code + base.Dispose(disposing); + } - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { this.components = new System.ComponentModel.Container(); this.nameTextBox = new System.Windows.Forms.TextBox(); this.nameLabel = new System.Windows.Forms.Label(); @@ -48,9 +49,12 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader this.getDataByQueryParamAndTemplateButton = new System.Windows.Forms.Button(); this.backgroundWorker2 = new System.ComponentModel.BackgroundWorker(); this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.buttonRemoveParam = new System.Windows.Forms.Button(); + this.buttonAddParam = new System.Windows.Forms.Button(); + this.labelParamValue = new System.Windows.Forms.Label(); + this.listBoxQueryParams = new System.Windows.Forms.ListBox(); + this.queryParamValueTextBox = new System.Windows.Forms.TextBox(); this.info5Button = new System.Windows.Forms.Button(); - this.label1 = new System.Windows.Forms.Label(); - this.queryParamTextBox = new System.Windows.Forms.TextBox(); this.backgroundWorker3 = new System.ComponentModel.BackgroundWorker(); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); this.groupBox4 = new System.Windows.Forms.GroupBox(); @@ -129,7 +133,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader // // info2Button // - this.info2Button.Location = new System.Drawing.Point(417, 19); + this.info2Button.Location = new System.Drawing.Point(417, 23); this.info2Button.Name = "info2Button"; this.info2Button.Size = new System.Drawing.Size(35, 23); this.info2Button.TabIndex = 21; @@ -160,16 +164,16 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader this.groupBox2.Controls.Add(this.info4Button); this.groupBox2.Controls.Add(this.textBox2); this.groupBox2.Controls.Add(this.getDataByQueryParamAndTemplateButton); - this.groupBox2.Location = new System.Drawing.Point(661, 233); + this.groupBox2.Location = new System.Drawing.Point(487, 233); this.groupBox2.Name = "groupBox2"; this.groupBox2.Size = new System.Drawing.Size(463, 422); this.groupBox2.TabIndex = 16; this.groupBox2.TabStop = false; - this.groupBox2.Text = "Complet query testing"; + this.groupBox2.Text = "Complete query testing"; // // info4Button // - this.info4Button.Location = new System.Drawing.Point(417, 19); + this.info4Button.Location = new System.Drawing.Point(417, 23); this.info4Button.Name = "info4Button"; this.info4Button.Size = new System.Drawing.Size(35, 23); this.info4Button.TabIndex = 22; @@ -194,45 +198,73 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader this.getDataByQueryParamAndTemplateButton.TabIndex = 17; this.getDataByQueryParamAndTemplateButton.Text = "Get data by query param and template"; this.getDataByQueryParamAndTemplateButton.UseVisualStyleBackColor = true; - this.getDataByQueryParamAndTemplateButton.Click += new System.EventHandler(this.getDataByQueryParamAndTemplateButton_Click); // // groupBox3 // + this.groupBox3.Controls.Add(this.buttonRemoveParam); + this.groupBox3.Controls.Add(this.buttonAddParam); + this.groupBox3.Controls.Add(this.labelParamValue); + this.groupBox3.Controls.Add(this.listBoxQueryParams); + this.groupBox3.Controls.Add(this.queryParamValueTextBox); this.groupBox3.Controls.Add(this.info5Button); - this.groupBox3.Controls.Add(this.label1); - this.groupBox3.Controls.Add(this.queryParamTextBox); - this.groupBox3.Location = new System.Drawing.Point(488, 87); + this.groupBox3.Location = new System.Drawing.Point(956, 87); this.groupBox3.Name = "groupBox3"; this.groupBox3.Size = new System.Drawing.Size(166, 568); this.groupBox3.TabIndex = 17; this.groupBox3.TabStop = false; - this.groupBox3.Text = "Query params from component interface testing"; + this.groupBox3.Text = "Component interface testing"; + // + // buttonRemoveParam + // + this.buttonRemoveParam.Location = new System.Drawing.Point(85, 69); + this.buttonRemoveParam.Name = "buttonRemoveParam"; + this.buttonRemoveParam.Size = new System.Drawing.Size(75, 23); + this.buttonRemoveParam.TabIndex = 25; + this.buttonRemoveParam.Text = "Remove"; + this.buttonRemoveParam.UseVisualStyleBackColor = true; + // + // buttonAddParam + // + this.buttonAddParam.Location = new System.Drawing.Point(6, 69); + this.buttonAddParam.Name = "buttonAddParam"; + this.buttonAddParam.Size = new System.Drawing.Size(75, 23); + this.buttonAddParam.TabIndex = 24; + this.buttonAddParam.Text = "Add"; + this.buttonAddParam.UseVisualStyleBackColor = true; + // + // labelParamValue + // + this.labelParamValue.AutoSize = true; + this.labelParamValue.Location = new System.Drawing.Point(6, 24); + this.labelParamValue.Name = "labelParamValue"; + this.labelParamValue.Size = new System.Drawing.Size(75, 13); + this.labelParamValue.TabIndex = 23; + this.labelParamValue.Text = "Query params:"; + // + // listBoxQueryParams + // + this.listBoxQueryParams.FormattingEnabled = true; + this.listBoxQueryParams.Location = new System.Drawing.Point(6, 98); + this.listBoxQueryParams.Name = "listBoxQueryParams"; + this.listBoxQueryParams.Size = new System.Drawing.Size(154, 459); + this.listBoxQueryParams.TabIndex = 22; + // + // queryParamValueTextBox + // + this.queryParamValueTextBox.Location = new System.Drawing.Point(6, 40); + this.queryParamValueTextBox.Name = "queryParamValueTextBox"; + this.queryParamValueTextBox.Size = new System.Drawing.Size(154, 20); + this.queryParamValueTextBox.TabIndex = 21; // // info5Button // - this.info5Button.Location = new System.Drawing.Point(125, 41); + this.info5Button.Location = new System.Drawing.Point(125, 15); this.info5Button.Name = "info5Button"; this.info5Button.Size = new System.Drawing.Size(35, 23); - this.info5Button.TabIndex = 21; + this.info5Button.TabIndex = 20; this.info5Button.Text = "Info"; this.info5Button.UseVisualStyleBackColor = true; // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(6, 50); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(68, 13); - this.label1.TabIndex = 19; - this.label1.Text = "QueryParam:"; - // - // queryParamTextBox - // - this.queryParamTextBox.Location = new System.Drawing.Point(6, 66); - this.queryParamTextBox.Name = "queryParamTextBox"; - this.queryParamTextBox.Size = new System.Drawing.Size(154, 20); - this.queryParamTextBox.TabIndex = 18; - // // contextMenuStrip1 // this.contextMenuStrip1.Name = "contextMenuStrip1"; @@ -262,7 +294,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader // // info1Button // - this.info1Button.Location = new System.Drawing.Point(417, 11); + this.info1Button.Location = new System.Drawing.Point(417, 14); this.info1Button.Name = "info1Button"; this.info1Button.Size = new System.Drawing.Size(35, 23); this.info1Button.TabIndex = 21; @@ -295,7 +327,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader this.groupBox5.Controls.Add(this.examples1Button); this.groupBox5.Controls.Add(this.queryTemplateTextBox); this.groupBox5.Controls.Add(this.queryTemplateLabel); - this.groupBox5.Location = new System.Drawing.Point(662, 87); + this.groupBox5.Location = new System.Drawing.Point(487, 87); this.groupBox5.Name = "groupBox5"; this.groupBox5.Size = new System.Drawing.Size(462, 140); this.groupBox5.TabIndex = 23; @@ -313,7 +345,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader // // info3Button // - this.info3Button.Location = new System.Drawing.Point(419, 11); + this.info3Button.Location = new System.Drawing.Point(419, 14); this.info3Button.Name = "info3Button"; this.info3Button.Size = new System.Drawing.Size(35, 23); this.info3Button.TabIndex = 25; @@ -322,7 +354,7 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader // // examples1Button // - this.examples1Button.Location = new System.Drawing.Point(338, 11); + this.examples1Button.Location = new System.Drawing.Point(338, 14); this.examples1Button.Name = "examples1Button"; this.examples1Button.Size = new System.Drawing.Size(75, 23); this.examples1Button.TabIndex = 24; @@ -378,36 +410,39 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader this.ResumeLayout(false); this.PerformLayout(); - } + } - #endregion + #endregion - private System.Windows.Forms.TextBox nameTextBox; - private System.Windows.Forms.Label nameLabel; + private System.Windows.Forms.TextBox nameTextBox; + private System.Windows.Forms.Label nameLabel; private System.Windows.Forms.Label classNameLabel; private System.Windows.Forms.Label dataStorageTypeLabel; private System.Windows.Forms.ComboBox dataStorageTypeComboBox; private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button info2Button; private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.Button connectToDataSourceButton; private System.ComponentModel.BackgroundWorker backgroundWorker1; private System.Windows.Forms.GroupBox groupBox2; - private System.ComponentModel.BackgroundWorker backgroundWorker2; + private System.Windows.Forms.Button info4Button; private System.Windows.Forms.TextBox textBox2; private System.Windows.Forms.Button getDataByQueryParamAndTemplateButton; + private System.ComponentModel.BackgroundWorker backgroundWorker2; private System.Windows.Forms.GroupBox groupBox3; - private System.ComponentModel.BackgroundWorker backgroundWorker3; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.TextBox queryParamTextBox; - private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; - private System.Windows.Forms.Button info2Button; - private System.Windows.Forms.Button info4Button; + private System.Windows.Forms.Button buttonRemoveParam; + private System.Windows.Forms.Button buttonAddParam; + private System.Windows.Forms.Label labelParamValue; + private System.Windows.Forms.ListBox listBoxQueryParams; + private System.Windows.Forms.TextBox queryParamValueTextBox; private System.Windows.Forms.Button info5Button; + private System.ComponentModel.BackgroundWorker backgroundWorker3; + private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.Label label2; private System.Windows.Forms.Button info1Button; private System.Windows.Forms.Label dataSourceLabel; private System.Windows.Forms.TextBox dataSourceTextBox; - private System.Windows.Forms.Label label2; private System.Windows.Forms.GroupBox groupBox5; private System.Windows.Forms.Label label3; private System.Windows.Forms.Button info3Button; @@ -415,4 +450,4 @@ namespace TBF.Rig.Input.DataStorage.UniDataStorageReader private System.Windows.Forms.TextBox queryTemplateTextBox; private System.Windows.Forms.Label queryTemplateLabel; } -} +} \ No newline at end of file diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index 3e78d7d5c..9f4ed694b 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -727,6 +727,8 @@ + + Form