Merge branch UniDataStorageReader

This commit is contained in:
Marek Frniak 2026-04-12 10:53:53 +02:00
commit 0b429ffbc2
27 changed files with 2542 additions and 12 deletions

View File

@ -0,0 +1,76 @@
using System.Collections.Generic;
using System.Text;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader
{
/// <summary>
/// Represents result of source/query diagnostic.
/// </summary>
public class ReaderDiagnosticResult
{
/// <summary>
/// Indicates whether the diagnostic operation was successful.
/// </summary>
public bool Success { get; set; }
/// <summary>
/// Short summary message.
/// </summary>
public string Message { get; set; }
/// <summary>
/// Optional detailed diagnostic log lines.
/// </summary>
public List<string> Diagnostics { get; set; }
/// <summary>
/// Optional payload returned by the diagnostic.
/// Example: header columns, file lines count, found index, etc.
/// </summary>
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<string>();
}
public string ToDisplayDiag()
{
StringBuilder sb = new StringBuilder();
if (Diagnostics != null && Diagnostics.Count > 0)
{
foreach (string line in Diagnostics)
{
sb.AppendLine(line);
}
if (!string.IsNullOrWhiteSpace(Message))
sb.AppendLine();
}
if (!string.IsNullOrWhiteSpace(Message))
sb.AppendLine(Message);
return sb.ToString();
}
}
}

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader
{
/// <summary>
/// Helper class to assign descriptions to enum values
/// </summary>
public class Description : Attribute
{
public string Text;
public Description(string t)
{
Text = t;
}
}
public static class GetDescription
{
/// Extension method for enum-s
public static string ToDescription(this Enum en)
{
Type type = en.GetType();
MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(Description), false);
if (attrs != null && attrs.Length > 0)
return ((Description)attrs[0]).Text;
}
return en.ToString(); /// Return ToString() value in case there is no description
}
}
/// <summary>
/// Identifies the type of data storage
/// </summary>
public enum DataStorageType
{
RestApi,
Database,
Json,
Csv
}
}

View File

@ -0,0 +1,38 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader
{
/// <summary>
/// Factory component 'UniDataStorageReader' implements more storing modules
/// Modules:
/// </summary>
public class Factory : IComponentFactory
{
public string ClassName { get { return GetType().Namespace.Substring(8); } } /// For backward compatibility
public override string ToString() { return ClassName; }
public IComponent DummyComponent() { return new Reader(new ReaderCfg("UniDataStorageReader", this)); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components)
{
ReaderCfg readerCfg = cfg as ReaderCfg;
if (readerCfg == null)
throw new ArgumentException("Invalid config for UniDataStorageReader");
return new Reader(readerCfg);
}
public IComponentCfg DefaultConfig() { return new ReaderCfg("UniDataStorageReader", this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(ReaderCfg.Serializer, component, this);
}
}
}

View File

@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader
{
/// <summary>
/// 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.
/// </summary>
public class DataQuery
{
/// <summary>
/// Parameter values used for repeated execution of the same query template.
/// </summary>
public List<string> QueryParams { get; } = new List<string>();
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader
{
public interface IDataStorageReader
{
object GetData(DataQuery query);
ReaderDiagnosticResult TestSource(bool enableDiagnostics);
ReaderDiagnosticResult TestQuery(bool enableDiagnostics);
}
}

View File

@ -0,0 +1,93 @@
using Common;
using Config.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TBF.Rig.Generic;
using TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers;
using TBF.Rig.Scales.MettlerToledo;
using static TBF.Rig.Input.DataStorage.UniDataStorageReader.ReaderCfg;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader
{
/// <summary>
/// Main component that selects appropriate data reader based on configuration.
/// Acts as a dispatcher between different storage implementations.
/// </summary>
public class Reader : IComponent
{
private readonly ReaderCfg cfg;
public Reader(ReaderCfg cfg)
{
this.cfg = cfg ?? throw new ArgumentNullException(nameof(cfg));
}
public string Name { get { return cfg.Name; } }
public string ClassName { get { return cfg.ClassName; } }
public string ParentName { get { return cfg.ParentName; } }
public DebugMode DebugLevel { get { return cfg.DebugLevel; } }
public LogLevel LogLevel { get { return cfg.LogLevel; } }
public IComponentCfg Cfg { get { return cfg; } }
public IList<MeasurementCorrection> Corrections { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public IList<Uncertainty> Uncertainties { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public object GetDataFromStorageByParameter(DataQuery query)
{
string storageType = (cfg.DataStorageType ?? string.Empty).Trim();
IDataStorageReader reader;
switch (storageType)
{
case StorageTypes.RestApi:
reader = new RestApiReader(cfg);
break;
case StorageTypes.RemoteDatabase:
case StorageTypes.LocalDatabase:
reader = new DatabaseReader(cfg);
break;
case StorageTypes.RemoteJson:
case StorageTypes.LocalJson:
reader = new JsonReader(cfg);
break;
case StorageTypes.RemoteCsv:
case StorageTypes.LocalCsv:
reader = new CsvReader(cfg);
break;
default:
throw new NotSupportedException(
$"Unsupported DataStorageType: '{cfg.DataStorageType}'");
}
return reader.GetData(query);
}
public void Initialize()
{
throw new NotImplementedException();
}
public void StartChangeHandler()
{
throw new NotImplementedException();
}
public void StopChangeHandler()
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,169 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Common;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.Resources;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader
{
///
/// Class and file name is preserved for backward compatibility
///
public class ReaderCfg : ComponentCfgBase, Generic.IComponentCfg, IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ReaderCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new ReaderCfgCtrl(); }
public string DataStorageType;
public string DataSource;
public string QueryTemplate;
/// Private parameterless constructor invoked by all other (public) constructors
ReaderCfg()
{
InitializeAll();
}
public ReaderCfg(string name, IComponentFactory factory)
: this()
{
this.Name = name;
this.Factory = factory;
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
DataStorageType = string.Empty;
DataSource = string.Empty;
QueryTemplate = string.Empty;
}
string[] paramNames = new string[]
{
"Data Storage type",
"Data source",
"Query template",
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
switch (i)
{
case 0:
return new string[]
{
StorageTypes.RestApi,
StorageTypes.RemoteDatabase,
StorageTypes.RemoteJson,
StorageTypes.RemoteCsv,
StorageTypes.LocalDatabase,
StorageTypes.LocalJson,
StorageTypes.LocalCsv,
};
case 1:
case 2:
default:
return null;
}
}
public string ToString(int i)
{
return string.Format("Name={0}, DataStorageType={1}",
Name,
DataStorageType);
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: DataStorageType = strValue; return CfgUpdateFlags.RestartRqrd;
case 1: DataSource = strValue; return CfgUpdateFlags.RestartRqrd;
case 2: QueryTemplate = strValue; return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
strValue = strValue ?? string.Empty;
switch (i)
{
case 0:
if (string.IsNullOrWhiteSpace(strValue))
{
message = "Data storage type must be selected.";
return false;
}
return true;
case 1:
if (string.IsNullOrWhiteSpace(strValue))
{
message = "Data source must not be empty.";
return false;
}
return true;
case 2:
if (string.IsNullOrWhiteSpace(strValue))
{
message = "Query template must not be empty.";
return false;
}
return true;
default:
message = "Invalid parameter index.";
return false;
}
}
void CopyContentTo(ReaderCfg prms)
{
prms.DataStorageType = this.DataStorageType;
prms.DataSource = this.DataSource;
prms.QueryTemplate = this.QueryTemplate;
}
public IParamsProvider Clone()
{
ReaderCfg pars = new ReaderCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
public static class StorageTypes
{
public const string RestApi = "REST_API";
public const string RemoteDatabase = "REMOTE_DATABASE";
public const string RemoteJson = "REMOTE_JSON";
public const string RemoteCsv = "REMOTE_CSV";
public const string LocalDatabase = "LOCAL_DATABASE";
public const string LocalJson = "LOCAL_JSON";
public const string LocalCsv = "LOCAL_CSV";
}
}
}

View File

@ -0,0 +1,345 @@
using System;
using System.Collections.Generic;
using System.IO;
using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers
{
/// <summary>
/// Reader implementation for CSV-based data source.
/// </summary>
public class CsvReader : IDataStorageReader
{
private string resolvedPath;
private string[] loadedLines;
private string[] loadedHeaders;
private readonly ReaderCfg cfg;
public CsvReader(ReaderCfg cfg)
{
this.cfg = cfg ?? throw new ArgumentNullException(nameof(cfg));
}
/// <summary>
/// Reads data from CSV and returns matched row data.
/// Executes the same query template for each value in DataQuery.QueryParams.
/// </summary>
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);
ReaderDiagnosticResult searchResult = ExecuteQuery(query, true);
if (!searchResult.Success)
throw new InvalidOperationException(searchResult.Message);
return searchResult;
}
/// <summary>
/// Tests whether the CSV source can be resolved, opened and read.
/// </summary>
public ReaderDiagnosticResult TestSource(bool enableDiagnostics)
{
return ConnectToSource(enableDiagnostics);
}
/// <summary>
/// Tests whether the configured query columns exist in the CSV source.
/// </summary>
public ReaderDiagnosticResult TestQuery(bool enableDiagnostics)
{
ReaderDiagnosticResult connectResult = ConnectToSource(enableDiagnostics);
if (!connectResult.Success)
return connectResult;
ReaderDiagnosticResult result = new ReaderDiagnosticResult();
try
{
Log(result, enableDiagnostics, "Starting QueryTemplate validation.");
SearchOrderDefinition definition = SearchOrderParser.Parse(cfg.QueryTemplate);
Log(result, enableDiagnostics, "QueryTemplate parsed successfully.");
Log(result, enableDiagnostics, "Select column: " + definition.SelectColumn);
Log(result, enableDiagnostics, "Where column: " + definition.WhereColumn);
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);
result.Success = true;
result.Message = "QueryTemplate validation finished successfully.";
result.Data = null;
}
catch (Exception ex)
{
result.Success = false;
result.Message = ex.Message;
result.Data = null;
Log(result, enableDiagnostics, "ERROR: " + ex.Message);
}
return result;
}
/// <summary>
/// Opens the CSV source, validates its existence and loads its content.
/// </summary>
public ReaderDiagnosticResult ConnectToSource(bool enableDiagnostics)
{
ReaderDiagnosticResult result = new ReaderDiagnosticResult();
try
{
Log(result, enableDiagnostics, "Starting CSV source connection test.");
if (string.IsNullOrWhiteSpace(cfg.DataSource))
throw new InvalidOperationException("CSV data source is empty.");
Log(result, enableDiagnostics, "Input data source: " + cfg.DataSource);
resolvedPath = Path.GetFullPath(cfg.DataSource);
Log(result, enableDiagnostics, "Resolved full path: " + resolvedPath);
Log(result, enableDiagnostics, "Checking whether the file exists.");
if (!File.Exists(resolvedPath))
throw new FileNotFoundException("CSV file was not found.", resolvedPath);
Log(result, enableDiagnostics, "CSV file exists.");
Log(result, enableDiagnostics, "Reading CSV file.");
loadedLines = File.ReadAllLines(resolvedPath);
if (loadedLines == null || loadedLines.Length == 0)
throw new InvalidOperationException("CSV file is empty.");
Log(result, enableDiagnostics, "CSV line count: " + loadedLines.Length);
loadedHeaders = SplitCsvLine(loadedLines[0]);
if (loadedHeaders == null || loadedHeaders.Length == 0)
throw new InvalidOperationException("CSV header is empty.");
Log(result, enableDiagnostics, "CSV header loaded successfully.");
Log(result, enableDiagnostics, "Header column count: " + loadedHeaders.Length);
result.Success = true;
result.Message = "CSV source connection finished successfully.";
result.Data = loadedLines;
}
catch (Exception ex)
{
result.Success = false;
result.Message = ex.Message;
result.Data = null;
Log(result, enableDiagnostics, "ERROR: " + ex.Message);
}
return result;
}
/// <summary>
/// Executes the configured query for all provided parameter values.
/// </summary>
private ReaderDiagnosticResult ExecuteQuery(DataQuery query, bool enableDiagnostics)
{
ReaderDiagnosticResult result = new ReaderDiagnosticResult();
try
{
Log(result, enableDiagnostics, "Starting QueryTemplate execution.");
if (query == null)
throw new InvalidOperationException("DataQuery is null.");
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.");
if (loadedHeaders == null || loadedHeaders.Length == 0)
throw new InvalidOperationException("CSV header is not loaded.");
SearchOrderDefinition definition = SearchOrderParser.Parse(cfg.QueryTemplate);
Log(result, enableDiagnostics, "QueryTemplate parsed successfully.");
Log(result, enableDiagnostics, "Select column: " + definition.SelectColumn);
Log(result, enableDiagnostics, "Where column: " + definition.WhereColumn);
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);
List<string> matchedValues = new List<string>();
int matchCount = 0;
for (int paramIndex = 0; paramIndex < query.QueryParams.Count; paramIndex++)
{
string queryValue = (query.QueryParams[paramIndex] ?? string.Empty).Trim();
Log(result, enableDiagnostics, string.Format("=== Query item {0} ===", paramIndex + 1));
Log(result, enableDiagnostics, "QueryParam: " + queryValue);
bool found = false;
for (int lineIndex = 1; lineIndex < loadedLines.Length; lineIndex++)
{
if (string.IsNullOrWhiteSpace(loadedLines[lineIndex]))
continue;
string[] values = SplitCsvLine(loadedLines[lineIndex]);
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.");
}
}
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;
}
catch (Exception ex)
{
result.Success = false;
result.Message = ex.Message;
result.Data = null;
Log(result, enableDiagnostics, "ERROR: " + ex.Message);
}
return result;
}
/// <summary>
/// Finds zero-based index of the requested column in CSV header.
/// </summary>
private int FindColumnIndex(string[] headers, string columnName)
{
for (int i = 0; i < headers.Length; i++)
{
if (string.Equals(
(headers[i] ?? string.Empty).Trim(),
(columnName ?? string.Empty).Trim(),
StringComparison.OrdinalIgnoreCase))
{
return i;
}
}
return -1;
}
/// <summary>
/// Splits CSV line by common separators.
/// Simple implementation without quoted-separator support.
/// </summary>
private string[] SplitCsvLine(string line)
{
if (string.IsNullOrEmpty(line))
return new string[0];
if (line.Contains(","))
return line.Split(',');
if (line.Contains(";"))
return line.Split(';');
if (line.Contains("\t"))
return line.Split('\t');
return new[] { line };
}
/// <summary>
/// Appends a diagnostic line if diagnostics are enabled.
/// </summary>
private void Log(ReaderDiagnosticResult result, bool enableDiagnostics, string message)
{
if (!enableDiagnostics || result == null)
return;
result.Diagnostics.Add(message);
}
private int ResolveColumnIndex(string[] headers, ColumnReference columnRef)
{
if (columnRef == null)
throw new InvalidOperationException("Column reference is null.");
if (columnRef.HasIndex)
{
int index = columnRef.Index.Value;
if (index < 0 || index >= headers.Length)
{
throw new InvalidOperationException(
string.Format("Column index {0} is out of range. Header column count: {1}.", index, headers.Length));
}
return index;
}
if (columnRef.HasName)
{
int index = FindColumnIndex(headers, columnRef.Name);
if (index < 0)
{
throw new InvalidOperationException(
string.Format("Column '{0}' was not found in CSV header.", columnRef.Name));
}
return index;
}
throw new InvalidOperationException("Column reference is not defined.");
}
}
}

View File

@ -0,0 +1,245 @@
using System;
using System.Collections.Generic;
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
{
/// <summary>
/// Reader implementation for SQL Server based data source.
/// DataSource = SQL Server connection string
/// QueryTemplate = SQL query containing QUERYPARAM placeholder
/// </summary>
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));
}
/// <summary>
/// Reads data from SQL Server and returns matched data.
/// If query returns 1 column, scalar value is returned.
/// If query returns multiple columns, Dictionary&lt;string, object&gt; is returned.
/// </summary>
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;
}
}
}
/// <summary>
/// Validates database connectivity and basic query readiness.
/// </summary>
public ReaderDiagnosticResult ConnectToSource(bool validateExistence)
{
if (string.IsNullOrWhiteSpace(cfg.DataSource))
return ReaderDiagnosticResult.Failure("Data source must not be empty.");
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));
}
}
private static string PrepareSqlText(string queryTemplate)
{
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");
}
private static void AddQueryParameters(SqlCommand command, object queryValue)
{
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];
}
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers
{
public class JsonReader : IDataStorageReader
{
private readonly ReaderCfg cfg;
public JsonReader(ReaderCfg cfg)
{
this.cfg = cfg ?? throw new ArgumentNullException(nameof(cfg));
}
public object GetData(DataQuery query)
{
if (string.IsNullOrWhiteSpace(cfg.DataSource))
throw new InvalidOperationException("JSON data source is empty.");
if (!File.Exists(cfg.DataSource))
throw new FileNotFoundException("JSON file not found.", cfg.DataSource);
string json = File.ReadAllText(cfg.DataSource);
// TODO: deserialize + filter
return json;
}
public ReaderDiagnosticResult TestQuery(bool enableDiagnostics)
{
throw new NotImplementedException();
}
public ReaderDiagnosticResult TestSource(bool enableDiagnostics)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers
{
public class RestApiReader : IDataStorageReader
{
private readonly ReaderCfg cfg;
public RestApiReader(ReaderCfg cfg)
{
this.cfg = cfg ?? throw new ArgumentNullException(nameof(cfg));
}
public object GetData(DataQuery query)
{
if (string.IsNullOrWhiteSpace(cfg.DataSource))
throw new InvalidOperationException("REST API data source is empty.");
// TODO: HTTP request
return null;
}
public ReaderDiagnosticResult TestQuery(bool enableDiagnostics)
{
throw new NotImplementedException();
}
public ReaderDiagnosticResult TestSource(bool enableDiagnostics)
{
throw new NotImplementedException();
}
}
}

View File

@ -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<string, string> Values { get; set; }
public CsvSearchResult()
{
Values = new Dictionary<string, string>();
}
}
}

View File

@ -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<string, object> Values { get; set; }
public DatabaseSearchResult()
{
Values = new Dictionary<string, object>();
}
}
}

View File

@ -0,0 +1,65 @@
using System;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching
{
/// <summary>
/// Parsed representation of QueryTemplate expression.
/// Example:
/// SELECT [Password] WHERE [PcbId] = QUERYPARAM
/// </summary>
public class SearchOrderDefinition
{
/// <summary>
/// Column to be returned.
/// </summary>
public ColumnReference SelectColumn { get; set; }
/// <summary>
/// Column used for lookup.
/// </summary>
public ColumnReference WhereColumn { get; set; }
}
/// <summary>
/// Represents a column reference either by name or by zero-based index.
/// </summary>
public class ColumnReference
{
/// <summary>
/// Column name if referenced by [ColumnName].
/// </summary>
public string Name { get; set; }
/// <summary>
/// Zero-based column index if referenced by COLUMN(n).
/// </summary>
public int? Index { get; set; }
/// <summary>
/// Returns true if reference is by column name.
/// </summary>
public bool HasName
{
get { return !string.IsNullOrWhiteSpace(Name); }
}
/// <summary>
/// Returns true if reference is by column index.
/// </summary>
public bool HasIndex
{
get { return Index.HasValue; }
}
public override string ToString()
{
if (HasName)
return "[" + Name + "]";
if (HasIndex)
return "COLUMN(" + Index.Value + ")";
return "<undefined column reference>";
}
}
}

View File

@ -0,0 +1,87 @@
using System;
using System.Text.RegularExpressions;
using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader
{
/// <summary>
/// Parses SQL-like QueryTemplate expressions.
/// Supported syntax:
/// SELECT [ReturnColumn] WHERE [MatchColumn] = QUERYPARAM
/// SELECT COLUMN(1) WHERE COLUMN(0) = QUERYPARAM
/// Mixed forms are also supported.
/// </summary>
public static class SearchOrderParser
{
private static readonly Regex FullPattern = new Regex(
@"^\s*SELECT\s+(?<select>\[[^\]]+\]|COLUMN\(\d+\))\s+WHERE\s+(?<where>\[[^\]]+\]|COLUMN\(\d+\))\s*=\s*QUERYPARAM\s*$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex NamedColumnPattern = new Regex(
@"^\[(?<name>[^\]]+)\]$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex IndexedColumnPattern = new Regex(
@"^COLUMN\((?<index>\d+)\)$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
/// <summary>
/// Parses QueryTemplate text into structured definition.
/// Throws if syntax is invalid.
/// </summary>
public static SearchOrderDefinition Parse(string searchOrder)
{
if (string.IsNullOrWhiteSpace(searchOrder))
throw new InvalidOperationException("QueryTemplate is empty.");
Match match = FullPattern.Match(searchOrder);
if (!match.Success)
{
throw new InvalidOperationException(
"Invalid QueryTemplate syntax. Expected: SELECT [ReturnColumn] WHERE [MatchColumn] = QUERYPARAM");
}
string selectToken = match.Groups["select"].Value;
string whereToken = match.Groups["where"].Value;
return new SearchOrderDefinition
{
SelectColumn = ParseColumnReference(selectToken),
WhereColumn = ParseColumnReference(whereToken)
};
}
/// <summary>
/// Parses one column reference token:
/// [ColumnName] or COLUMN(number)
/// </summary>
private static ColumnReference ParseColumnReference(string token)
{
if (string.IsNullOrWhiteSpace(token))
throw new InvalidOperationException("Column reference token is empty.");
Match nameMatch = NamedColumnPattern.Match(token);
if (nameMatch.Success)
{
return new ColumnReference
{
Name = nameMatch.Groups["name"].Value.Trim(),
Index = null
};
}
Match indexMatch = IndexedColumnPattern.Match(token);
if (indexMatch.Success)
{
return new ColumnReference
{
Name = null,
Index = int.Parse(indexMatch.Groups["index"].Value)
};
}
throw new InvalidOperationException(
"Invalid column reference '" + token + "'. Use [ColumnName] or COLUMN(number).");
}
}
}

View File

@ -0,0 +1,58 @@
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.UI
{
partial class xamplesForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.mainPanel = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// mainPanel
//
this.mainPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.mainPanel.Location = new System.Drawing.Point(0, 0);
this.mainPanel.Name = "mainPanel";
this.mainPanel.Size = new System.Drawing.Size(384, 161);
this.mainPanel.TabIndex = 0;
//
// xamplesForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(384, 161);
this.Controls.Add(this.mainPanel);
this.Name = "xamplesForm";
this.Text = "Examples";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel mainPanel;
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader.UI
{
public partial class xamplesForm : Form
{
public xamplesForm()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,378 @@
using Common;
using System;
using System.Collections.Generic;
using System.Text;
using TBF.Rig.Generic;
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
{
/// <summary>
/// UI configuration control for UniDataStorageReader.
/// Provides testing capabilities for data source and query execution.
/// </summary>
public partial class ReaderCfgCtrl : Configs.ConfigCtrlUtils, IComponentCfgCtrl
{
private readonly List<string> batchQueryParamValues = new List<string>();
public bool ShowMore { get { return false; } }
private ReaderCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as ReaderCfg;
Redraw();
}
}
public ReaderCfgCtrl()
{
InitializeComponent();
connectToDataSourceButton.Click += testByDataSourceButton_Click;
getDataByQueryParamAndTemplateButton.Click += getDataByQueryParamAndTemplateButton_Click;
buttonAddParam.Click += buttonAddParam_Click;
buttonRemoveParam.Click += buttonRemoveParam_Click;
}
private void ReaderCfgCtrl_Load(object sender, EventArgs e)
{
if (config == null) return;
Redraw();
}
public void Closing()
{
}
/// <summary>
/// Refreshes UI with current configuration values.
/// </summary>
private void Redraw()
{
if (config == null) return;
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
dataSourceTextBox.Text = config.DataSource;
queryTemplateTextBox.Text = config.QueryTemplate;
var values = config.ParamValues(0);
dataStorageTypeComboBox.Items.Clear();
if (values != null)
{
foreach (var item in values)
{
dataStorageTypeComboBox.Items.Add(item);
}
}
dataStorageTypeComboBox.Text = config.DataStorageType;
RefreshQueryParamsListBox();
}
/// <summary>
/// Enables editing controls.
/// </summary>
public void Unlock()
{
nameTextBox.Enabled = true;
dataStorageTypeComboBox.Enabled = true;
dataSourceTextBox.Enabled = true;
queryTemplateTextBox.Enabled = true;
textBox1.Enabled = true;
textBox1.ReadOnly = true;
textBox2.Enabled = true;
textBox2.ReadOnly = true;
queryParamValueTextBox.Enabled = true;
listBoxQueryParams.Enabled = true;
buttonAddParam.Enabled = true;
buttonRemoveParam.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
return CfgUpdateFlags.None;
}
/// <summary>
/// Applies changes from UI into configuration.
/// </summary>
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
if (config == null) return CfgUpdateFlags.Error;
if (config.Name != nameTextBox.Text)
{
config.Name = nameTextBox.Text;
flags |= (CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
}
flags |= UpdateDifferent(ref config.DataStorageType, dataStorageTypeComboBox.Text, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
flags |= UpdateDifferent(ref config.DataSource, dataSourceTextBox.Text, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
flags |= UpdateDifferent(ref config.QueryTemplate, queryTemplateTextBox.Text, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
return flags;
}
/// <summary>
/// Builds temporary configuration from UI.
/// Used by test actions so saved configuration is not required.
/// </summary>
private ReaderCfg BuildTemporaryConfigFromUi()
{
ReaderCfg tmpCfg = new ReaderCfg(
string.IsNullOrWhiteSpace(nameTextBox.Text) ? "UniDataStorageReader" : nameTextBox.Text,
config != null ? config.Factory : new Factory());
tmpCfg.DataStorageType = (dataStorageTypeComboBox.Text ?? string.Empty).Trim();
tmpCfg.DataSource = dataSourceTextBox.Text;
tmpCfg.QueryTemplate = queryTemplateTextBox.Text;
return tmpCfg;
}
/// <summary>
/// Creates appropriate reader implementation based on selected storage type.
/// </summary>
private IDataStorageReader CreateReader(ReaderCfg cfg)
{
switch ((cfg.DataStorageType ?? string.Empty).Trim())
{
case StorageTypes.RestApi:
return new RestApiReader(cfg);
case StorageTypes.RemoteDatabase:
case StorageTypes.LocalDatabase:
return new DatabaseReader(cfg);
case StorageTypes.RemoteJson:
case StorageTypes.LocalJson:
return new JsonReader(cfg);
case StorageTypes.RemoteCsv:
case StorageTypes.LocalCsv:
return new CsvReader(cfg);
default:
throw new NotSupportedException(
string.Format("Unsupported DataStorageType: '{0}'", cfg.DataStorageType));
}
}
/// <summary>
/// Calls reader diagnostic for source validation and displays the result.
/// </summary>
private void testByDataSourceButton_Click(object sender, EventArgs e)
{
textBox1.Clear();
try
{
ReaderCfg tmpCfg = BuildTemporaryConfigFromUi();
IDataStorageReader reader = CreateReader(tmpCfg);
ReaderDiagnosticResult result = reader.TestSource(true);
textBox1.Text = BuildDiagnosticHeader(tmpCfg, "Source test") + result.ToDisplayDiag();
}
catch (Exception ex)
{
textBox1.Text = BuildExceptionText("Data source test failed", ex);
}
}
/// <summary>
/// Executes query using values from the batch list only.
/// </summary>
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 ?? "<null>"));
}
}
else if (queryResult is ReaderDiagnosticResult diagResult)
{
sb.AppendLine(diagResult.ToDisplayDiag());
}
else
{
sb.AppendLine(queryResult != null ? queryResult.ToString() : "<null>");
}
sb.AppendLine();
}
textBox2.Text = sb.ToString();
}
catch (Exception ex)
{
textBox2.Text = BuildExceptionText("GetData test failed", ex);
}
}
/// <summary>
/// Adds a single batch test value into the list.
/// </summary>
private void buttonAddParam_Click(object sender, EventArgs e)
{
string value = queryParamValueTextBox.Text?.Trim();
if (string.IsNullOrWhiteSpace(value))
return;
batchQueryParamValues.Add(value);
queryParamValueTextBox.Clear();
RefreshQueryParamsListBox();
}
/// <summary>
/// Removes the selected batch test value from the list.
/// </summary>
private void buttonRemoveParam_Click(object sender, EventArgs e)
{
int index = listBoxQueryParams.SelectedIndex;
if (index < 0 || index >= batchQueryParamValues.Count)
return;
batchQueryParamValues.RemoveAt(index);
RefreshQueryParamsListBox();
}
/// <summary>
/// Refreshes ListBox content and shows line numbering.
/// </summary>
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]));
}
}
/// <summary>
/// Builds common header for diagnostic output.
/// </summary>
private string BuildDiagnosticHeader(ReaderCfg cfg, string testName)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("=== " + testName + " ===");
sb.AppendLine("Storage type: " + StorageTypeToDisplayName(cfg.DataStorageType));
sb.AppendLine("Data source: " + Safe(cfg.DataSource));
sb.AppendLine("Query template: " + Safe(cfg.QueryTemplate));
sb.AppendLine();
return sb.ToString();
}
/// <summary>
/// Builds exception text including inner exceptions.
/// </summary>
private string BuildExceptionText(string title, Exception ex)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(title + ":");
sb.AppendLine(ex.Message);
Exception inner = ex.InnerException;
while (inner != null)
{
sb.AppendLine();
sb.AppendLine("Inner exception:");
sb.AppendLine(inner.Message);
inner = inner.InnerException;
}
return sb.ToString();
}
/// <summary>
/// Returns safe printable text for diagnostics.
/// </summary>
private string Safe(string text)
{
return string.IsNullOrWhiteSpace(text) ? "<empty>" : text;
}
/// <summary>
/// Converts internal storage type identifier to user-friendly name.
/// </summary>
private string StorageTypeToDisplayName(string storageType)
{
switch ((storageType ?? string.Empty).Trim())
{
case StorageTypes.RestApi:
return "REST API";
case StorageTypes.RemoteDatabase:
return "Remote database";
case StorageTypes.RemoteJson:
return "Remote JSON";
case StorageTypes.RemoteCsv:
return "Remote CSV";
case StorageTypes.LocalDatabase:
return "Local database";
case StorageTypes.LocalJson:
return "Local JSON";
case StorageTypes.LocalCsv:
return "Local CSV";
default:
return Safe(storageType);
}
}
}
}

View File

@ -0,0 +1,453 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
namespace TBF.Rig.Input.DataStorage.UniDataStorageReader
{
partial class ReaderCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.dataStorageTypeLabel = new System.Windows.Forms.Label();
this.dataStorageTypeComboBox = new System.Windows.Forms.ComboBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.info2Button = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.connectToDataSourceButton = new System.Windows.Forms.Button();
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.info4Button = new System.Windows.Forms.Button();
this.textBox2 = new System.Windows.Forms.TextBox();
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.backgroundWorker3 = new System.ComponentModel.BackgroundWorker();
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.groupBox4 = new System.Windows.Forms.GroupBox();
this.label2 = new System.Windows.Forms.Label();
this.info1Button = new System.Windows.Forms.Button();
this.dataSourceLabel = new System.Windows.Forms.Label();
this.dataSourceTextBox = new System.Windows.Forms.TextBox();
this.groupBox5 = new System.Windows.Forms.GroupBox();
this.label3 = new System.Windows.Forms.Label();
this.info3Button = new System.Windows.Forms.Button();
this.examples1Button = new System.Windows.Forms.Button();
this.queryTemplateTextBox = new System.Windows.Forms.TextBox();
this.queryTemplateLabel = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.groupBox4.SuspendLayout();
this.groupBox5.SuspendLayout();
this.SuspendLayout();
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(117, 32);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(326, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(5, 35);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(38, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name:";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(114, 10);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComonentName";
//
// dataStorageTypeLabel
//
this.dataStorageTypeLabel.AutoSize = true;
this.dataStorageTypeLabel.Location = new System.Drawing.Point(5, 61);
this.dataStorageTypeLabel.Name = "dataStorageTypeLabel";
this.dataStorageTypeLabel.Size = new System.Drawing.Size(94, 13);
this.dataStorageTypeLabel.TabIndex = 5;
this.dataStorageTypeLabel.Text = "Data storage type:";
//
// dataStorageTypeComboBox
//
this.dataStorageTypeComboBox.Enabled = false;
this.dataStorageTypeComboBox.FormattingEnabled = true;
this.dataStorageTypeComboBox.Location = new System.Drawing.Point(117, 58);
this.dataStorageTypeComboBox.Name = "dataStorageTypeComboBox";
this.dataStorageTypeComboBox.Size = new System.Drawing.Size(326, 21);
this.dataStorageTypeComboBox.TabIndex = 9;
//
// groupBox1
//
this.groupBox1.Controls.Add(this.info2Button);
this.groupBox1.Controls.Add(this.textBox1);
this.groupBox1.Controls.Add(this.connectToDataSourceButton);
this.groupBox1.Location = new System.Drawing.Point(8, 233);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(473, 422);
this.groupBox1.TabIndex = 15;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Data storage source testing";
//
// info2Button
//
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;
this.info2Button.Text = "Info";
this.info2Button.UseVisualStyleBackColor = true;
//
// textBox1
//
this.textBox1.Enabled = false;
this.textBox1.Location = new System.Drawing.Point(15, 47);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBox1.Size = new System.Drawing.Size(437, 358);
this.textBox1.TabIndex = 15;
//
// connectToDataSourceButton
//
this.connectToDataSourceButton.Location = new System.Drawing.Point(15, 19);
this.connectToDataSourceButton.Name = "connectToDataSourceButton";
this.connectToDataSourceButton.Size = new System.Drawing.Size(131, 23);
this.connectToDataSourceButton.TabIndex = 14;
this.connectToDataSourceButton.Text = "Connect to Data source";
this.connectToDataSourceButton.UseVisualStyleBackColor = true;
//
// groupBox2
//
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(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 = "Complete query testing";
//
// info4Button
//
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;
this.info4Button.Text = "Info";
this.info4Button.UseVisualStyleBackColor = true;
//
// textBox2
//
this.textBox2.Enabled = false;
this.textBox2.Location = new System.Drawing.Point(6, 48);
this.textBox2.Multiline = true;
this.textBox2.Name = "textBox2";
this.textBox2.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBox2.Size = new System.Drawing.Size(446, 357);
this.textBox2.TabIndex = 18;
//
// getDataByQueryParamAndTemplateButton
//
this.getDataByQueryParamAndTemplateButton.Location = new System.Drawing.Point(6, 19);
this.getDataByQueryParamAndTemplateButton.Name = "getDataByQueryParamAndTemplateButton";
this.getDataByQueryParamAndTemplateButton.Size = new System.Drawing.Size(206, 23);
this.getDataByQueryParamAndTemplateButton.TabIndex = 17;
this.getDataByQueryParamAndTemplateButton.Text = "Get data by query param and template";
this.getDataByQueryParamAndTemplateButton.UseVisualStyleBackColor = true;
//
// 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.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 = "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, 15);
this.info5Button.Name = "info5Button";
this.info5Button.Size = new System.Drawing.Size(35, 23);
this.info5Button.TabIndex = 20;
this.info5Button.Text = "Info";
this.info5Button.UseVisualStyleBackColor = true;
//
// contextMenuStrip1
//
this.contextMenuStrip1.Name = "contextMenuStrip1";
this.contextMenuStrip1.Size = new System.Drawing.Size(61, 4);
//
// groupBox4
//
this.groupBox4.Controls.Add(this.label2);
this.groupBox4.Controls.Add(this.info1Button);
this.groupBox4.Controls.Add(this.dataSourceLabel);
this.groupBox4.Controls.Add(this.dataSourceTextBox);
this.groupBox4.Location = new System.Drawing.Point(8, 87);
this.groupBox4.Name = "groupBox4";
this.groupBox4.Size = new System.Drawing.Size(473, 140);
this.groupBox4.TabIndex = 22;
this.groupBox4.TabStop = false;
this.groupBox4.Text = "Data storage source setting";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(6, 25);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(106, 13);
this.label2.TabIndex = 22;
this.label2.Text = "Data storage source:";
//
// info1Button
//
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;
this.info1Button.Text = "Info";
this.info1Button.UseVisualStyleBackColor = true;
//
// dataSourceLabel
//
this.dataSourceLabel.AutoSize = true;
this.dataSourceLabel.Location = new System.Drawing.Point(-123, 1);
this.dataSourceLabel.Name = "dataSourceLabel";
this.dataSourceLabel.Size = new System.Drawing.Size(71, 13);
this.dataSourceLabel.TabIndex = 18;
this.dataSourceLabel.Text = " Data source:";
//
// dataSourceTextBox
//
this.dataSourceTextBox.Enabled = false;
this.dataSourceTextBox.Location = new System.Drawing.Point(6, 38);
this.dataSourceTextBox.Multiline = true;
this.dataSourceTextBox.Name = "dataSourceTextBox";
this.dataSourceTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.dataSourceTextBox.Size = new System.Drawing.Size(446, 89);
this.dataSourceTextBox.TabIndex = 17;
//
// groupBox5
//
this.groupBox5.Controls.Add(this.label3);
this.groupBox5.Controls.Add(this.info3Button);
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(487, 87);
this.groupBox5.Name = "groupBox5";
this.groupBox5.Size = new System.Drawing.Size(462, 140);
this.groupBox5.TabIndex = 23;
this.groupBox5.TabStop = false;
this.groupBox5.Text = "Query template setting";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(6, 22);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(81, 13);
this.label3.TabIndex = 26;
this.label3.Text = "Query template:";
//
// info3Button
//
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;
this.info3Button.Text = "Info";
this.info3Button.UseVisualStyleBackColor = true;
//
// examples1Button
//
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;
this.examples1Button.Text = "Examples";
this.examples1Button.UseVisualStyleBackColor = true;
//
// queryTemplateTextBox
//
this.queryTemplateTextBox.Enabled = false;
this.queryTemplateTextBox.Location = new System.Drawing.Point(8, 38);
this.queryTemplateTextBox.Multiline = true;
this.queryTemplateTextBox.Name = "queryTemplateTextBox";
this.queryTemplateTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.queryTemplateTextBox.Size = new System.Drawing.Size(446, 89);
this.queryTemplateTextBox.TabIndex = 23;
//
// queryTemplateLabel
//
this.queryTemplateLabel.AutoSize = true;
this.queryTemplateLabel.Location = new System.Drawing.Point(-123, 6);
this.queryTemplateLabel.Name = "queryTemplateLabel";
this.queryTemplateLabel.Size = new System.Drawing.Size(81, 13);
this.queryTemplateLabel.TabIndex = 22;
this.queryTemplateLabel.Text = "Query template:";
//
// ReaderCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.groupBox5);
this.Controls.Add(this.groupBox4);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.dataStorageTypeComboBox);
this.Controls.Add(this.dataStorageTypeLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "ReaderCfgCtrl";
this.Size = new System.Drawing.Size(1135, 671);
this.Load += new System.EventHandler(this.ReaderCfgCtrl_Load);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.groupBox3.PerformLayout();
this.groupBox4.ResumeLayout(false);
this.groupBox4.PerformLayout();
this.groupBox5.ResumeLayout(false);
this.groupBox5.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
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.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.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.GroupBox groupBox5;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Button info3Button;
private System.Windows.Forms.Button examples1Button;
private System.Windows.Forms.TextBox queryTemplateTextBox;
private System.Windows.Forms.Label queryTemplateLabel;
}
}

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="backgroundWorker1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="backgroundWorker2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>179, 17</value>
</metadata>
<metadata name="backgroundWorker3.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>341, 17</value>
</metadata>
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>503, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>44</value>
</metadata>
</root>

View File

@ -159,7 +159,7 @@ namespace TBF.Rig.Output.DB.DatabaseWriter
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "WriteDbCfgCtrl";
this.Name = "WriteDBCfgCtrl";
this.Size = new System.Drawing.Size(450, 250);
this.Load += new System.EventHandler(this.WriterCfgCtrl_Load);
this.ResumeLayout(false);

View File

@ -11,6 +11,9 @@ using TBF.Resources;
namespace TBF.Rig.Output.FileWriters.IperlLogger
{
///
/// Class and file name is preserved for backward compatibility
///
public class WriterCfg : ComponentCfgBase, Generic.IComponentCfg, IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(WriterCfg) })[0];

View File

@ -92,6 +92,7 @@ namespace TBF.Rig
new Network.Camera.RoiForFixedStartKeyence.Factory(),
new Network.Comet.Ambient.Factory(),
new Network.RestAPI.Factory(),
new Input.DataStorage.UniDataStorageReader.Factory(),
new Output.DataStorage.UniDataStorageWriter.Factory(),
new Output.DB.DatabaseWriter.Factory(),
new Output.DB.ProductionTracing.Factory(),

View File

@ -721,6 +721,33 @@
<Compile Include="Rig\Hart\Nivotrack\Nivotrack.cs" />
<Compile Include="Rig\Hart\Nivotrack\NivotrackCfg.cs" />
<Compile Include="Rig\HeatMetersPath.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Diagnostic\ReaderDiagnosticResult.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Enums.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Factory.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Interfaces\DataQuery.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Interfaces\IDataStorageReader.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Reader.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Searching\Csv\CsvSearchResult.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Searching\Database\DatabaseSearchResult.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\UI\ExamplesFrm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\UI\ExamplesFrm.Designer.cs">
<DependentUpon>ExamplesFrm.cs</DependentUpon>
</Compile>
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\UI\ReaderCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\UI\ReaderCfgCtrl.designer.cs">
<DependentUpon>ReaderCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\ReaderCfg.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Readers\CsvReader .cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Readers\DatabaseReader .cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Readers\JsonReader .cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Readers\RestApiReader .cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Searching\SearchOrderDefinition.cs" />
<Compile Include="Rig\Input\DataStorage\UniDataStorageReader\Searching\SearchOrderParser.cs" />
<Compile Include="Rig\Keithley\Multimeter_2010_RS232\Factory.cs" />
<Compile Include="Rig\Keithley\Multimeter_2010_RS232\Multimeter.cs" />
<Compile Include="Rig\Keithley\Multimeter_2010_RS232\MultimeterCfg.cs" />
@ -1078,7 +1105,9 @@
<Compile Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.designer.cs" />
<Compile Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.designer.cs">
<DependentUpon>WriteDBCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\Output\DB\DatabaseWriter\WriterCfg.cs" />
<Compile Include="Rig\Output\DB\DatabaseWriter\WritingToDB.cs" />
<Compile Include="Rig\Output\DB\ProductionTracing\Tracing.cs" />
@ -3424,6 +3453,12 @@
<EmbeddedResource Include="Rig\Dummy\RegValve\RegulValveCfgCtrl.resx">
<DependentUpon>RegulValveCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Input\DataStorage\UniDataStorageReader\UI\ExamplesFrm.resx">
<DependentUpon>ExamplesFrm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Input\DataStorage\UniDataStorageReader\UI\ReaderCfgCtrl.resx">
<DependentUpon>ReaderCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Keithley\Multimeter_2010_RS232\MultimeterCfgCtrl.resx">
<DependentUpon>MultimeterCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
@ -3513,7 +3548,9 @@
<DependentUpon>WriterCfgCtrl.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.resx" />
<EmbeddedResource Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.resx">
<DependentUpon>WriteDBCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\Output\DB\ProductionTracing\TracingCfgCtrl.resx">
<DependentUpon>TracingCfgCtrl.cs</DependentUpon>
</EmbeddedResource>

View File

@ -739,7 +739,7 @@
<value>processTabPageCtrl</value>
</data>
<data name="&gt;&gt;processTabPageCtrl.Type" xml:space="preserve">
<value>TBF.UI.Process.ProcessTabPageCtrl, TBF, Version=3.9.2149.4, Culture=neutral, PublicKeyToken=null</value>
<value>TBF.UI.Process.ProcessTabPageCtrl, TBF, Version=3.9.3001.1, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;processTabPageCtrl.Parent" xml:space="preserve">
<value>processTabPage</value>
@ -817,7 +817,7 @@
<value>resultsTabPageCtrl</value>
</data>
<data name="&gt;&gt;resultsTabPageCtrl.Type" xml:space="preserve">
<value>TBF.UI.ResultsMI.ResultsTabPageCtrl, TBF, Version=3.9.2149.4, Culture=neutral, PublicKeyToken=null</value>
<value>TBF.UI.ResultsMI.ResultsTabPageCtrl, TBF, Version=3.9.3001.1, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;resultsTabPageCtrl.Parent" xml:space="preserve">
<value>resultsTabPage</value>
@ -871,7 +871,7 @@
<value>graphsTabPageCtrl</value>
</data>
<data name="&gt;&gt;graphsTabPageCtrl.Type" xml:space="preserve">
<value>TBF.UI.Graphs.GraphsTabPageCtrl, TBF, Version=3.9.2149.4, Culture=neutral, PublicKeyToken=null</value>
<value>TBF.UI.Graphs.GraphsTabPageCtrl, TBF, Version=3.9.3001.1, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;graphsTabPageCtrl.Parent" xml:space="preserve">
<value>graphsTabPage</value>
@ -925,7 +925,7 @@
<value>eventLogsTabPageCtrl</value>
</data>
<data name="&gt;&gt;eventLogsTabPageCtrl.Type" xml:space="preserve">
<value>TBF.UI.EventLogs.EventLogsTabPageCtrl, TBF, Version=3.9.2149.4, Culture=neutral, PublicKeyToken=null</value>
<value>TBF.UI.EventLogs.EventLogsTabPageCtrl, TBF, Version=3.9.3001.1, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;eventLogsTabPageCtrl.Parent" xml:space="preserve">
<value>eventLogsTabPage</value>
@ -979,7 +979,7 @@
<value>calendarTabPageCtrl</value>
</data>
<data name="&gt;&gt;calendarTabPageCtrl.Type" xml:space="preserve">
<value>TBF.UI.Calendar.CalendarTabPageCtrl, TBF, Version=3.9.2149.4, Culture=neutral, PublicKeyToken=null</value>
<value>TBF.UI.Calendar.CalendarTabPageCtrl, TBF, Version=3.9.3001.1, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;calendarTabPageCtrl.Parent" xml:space="preserve">
<value>calendarTabPage</value>
@ -1033,7 +1033,7 @@
<value>picturesTabPageCtrl</value>
</data>
<data name="&gt;&gt;picturesTabPageCtrl.Type" xml:space="preserve">
<value>TBF.UI.Camera.PicturesTabPageCtrl, TBF, Version=3.9.2149.4, Culture=neutral, PublicKeyToken=null</value>
<value>TBF.UI.Camera.PicturesTabPageCtrl, TBF, Version=3.9.3001.1, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;picturesTabPageCtrl.Parent" xml:space="preserve">
<value>picturesTabPage</value>

View File

@ -89,10 +89,10 @@ namespace TBF.UI.Settings
resources.ApplyResources(this.benchNameTextBox, "benchNameTextBox");
this.benchNameTextBox.Name = "benchNameTextBox";
//
// connectionStringLabel
// dataSourceLabel
//
resources.ApplyResources(this.connectionStringLabel, "connectionStringLabel");
this.connectionStringLabel.Name = "connectionStringLabel";
resources.ApplyResources(this.connectionStringLabel, "dataSourceLabel");
this.connectionStringLabel.Name = "dataSourceLabel";
//
// configDbConnectionStringTextBox
//