Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AssemblyName>Omika.RendezVousProbe</AssemblyName>
|
||||
<RootNamespace>Omika.RendezVousProbe</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Omika.Data\Omika.Data.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
|
||||
<PackageReference Include="System.Data.OleDb" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,146 @@
|
||||
// Probe LECTURE SEULE ciblé RendezVous.
|
||||
// Reproduit EXACTEMENT le mécanisme de connexion de l'API
|
||||
// (BusinessOleDbConnection -> HfSqlOleDbConnectionFactory -> BuildExtendedPropertiesFromFilePasswords)
|
||||
// pour lire Planning_RDV sur BATIK_TEST et identifier les lignes où PL_DateFin < PL_DateDebut.
|
||||
//
|
||||
// Aucune écriture. Aucun password affiché. Aucune donnée personnelle loggée
|
||||
// (nom client, personne, adresse, notes, téléphone, email).
|
||||
// Seuls PL_PKID (identifiant technique) et les valeurs brutes DATE/HEURE sont affichés.
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Omika.Data.Configuration;
|
||||
using Omika.Data.Connection;
|
||||
using Omika.Data.HfSql.Connection;
|
||||
|
||||
// --- 1. Charger la configuration Hfsql (avec FilePasswords) ---
|
||||
var configPath = Path.GetFullPath(Path.Combine(
|
||||
Directory.GetCurrentDirectory(),
|
||||
"config", "hfsql-test.local.json"));
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddJsonFile(configPath, optional: false, reloadOnChange: false)
|
||||
.Build();
|
||||
|
||||
var hfsqlOptions = new HfsqlOptions();
|
||||
config.GetSection(HfsqlOptions.SectionName).Bind(hfsqlOptions);
|
||||
|
||||
Console.WriteLine($"=== Probe RendezVous (base {hfsqlOptions.DatabaseName}) ===");
|
||||
Console.WriteLine();
|
||||
|
||||
// --- 2. Reproduire le mécanisme de l'API : BusinessOleDbConnection ---
|
||||
var factory = new HfSqlOleDbConnectionFactory();
|
||||
await using var business = new BusinessOleDbConnection(hfsqlOptions, factory);
|
||||
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
int totalRows = 0;
|
||||
int countInvalid = 0;
|
||||
int countCrossMidnight = 0;
|
||||
int countAnomalyPure = 0;
|
||||
long? firstInvalidPk = null;
|
||||
DateTime? firstInvalidStart = null;
|
||||
DateTime? firstInvalidEnd = null;
|
||||
|
||||
try
|
||||
{
|
||||
await business.OpenAsync();
|
||||
Console.WriteLine("Connexion OLE DB ouverte (mécanisme API).");
|
||||
|
||||
// --- 3. Lire les colonnes DATE/HEURE de Planning_RDV ---
|
||||
// Même périmètre que le repository (SearchAsync) : toutes les lignes.
|
||||
string sql = "SELECT PL_PKID, PL_DateDebut, PL_DateFin FROM Planning_RDV";
|
||||
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
|
||||
var rows = await business.QueryAsync(sql, cancellationToken: cts.Token);
|
||||
|
||||
totalRows = rows.Count;
|
||||
Console.WriteLine($"rows lues = {totalRows}");
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
long pk = ToLong(row, "PL_PKID");
|
||||
DateTime start = ToDateTime(row, "PL_DateDebut");
|
||||
DateTime end = ToDateTime(row, "PL_DateFin");
|
||||
|
||||
if (end < start)
|
||||
{
|
||||
countInvalid++;
|
||||
if (firstInvalidPk is null)
|
||||
{
|
||||
firstInvalidPk = pk;
|
||||
firstInvalidStart = start;
|
||||
firstInvalidEnd = end;
|
||||
}
|
||||
|
||||
// Distinguer un éventuel rendez-vous à cheval sur minuit
|
||||
// (fin le lendemain du début) d'une anomalie pure (fin avant début).
|
||||
// Cross-midnight : la fin est le jour suivant le début.
|
||||
bool isCrossMidnight = end.Date == start.Date.AddDays(1);
|
||||
if (isCrossMidnight)
|
||||
{
|
||||
countCrossMidnight++;
|
||||
}
|
||||
else
|
||||
{
|
||||
countAnomalyPure++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("--- Résultat ---");
|
||||
Console.WriteLine($"rows = {totalRows}");
|
||||
Console.WriteLine($"count_invalid (PL_DateFin < PL_DateDebut) = {countInvalid}");
|
||||
Console.WriteLine($" dont cross-midnight (fin = lendemain du début) = {countCrossMidnight}");
|
||||
Console.WriteLine($" dont anomalie pure (fin avant début, hors lendemain) = {countAnomalyPure}");
|
||||
Console.WriteLine($"elapsed = {sw.ElapsedMilliseconds} ms");
|
||||
|
||||
if (firstInvalidPk is not null)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("--- Première ligne invalide (technique, non sensible) ---");
|
||||
Console.WriteLine($"PL_PKID = {firstInvalidPk}");
|
||||
Console.WriteLine($"PL_DateDebut (brut) = {firstInvalidStart:O}");
|
||||
Console.WriteLine($"PL_DateFin (brut) = {firstInvalidEnd:O}");
|
||||
Console.WriteLine($"start calculé = {firstInvalidStart:O}");
|
||||
Console.WriteLine($"end calculé = {firstInvalidEnd:O}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Aucune ligne invalide détectée.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sw.Stop();
|
||||
Console.WriteLine($"ERREUR: {ex.Message}");
|
||||
Console.WriteLine($"elapsed = {sw.ElapsedMilliseconds} ms");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Probe RendezVous terminé (lecture seule).");
|
||||
|
||||
// --- Helpers ---
|
||||
|
||||
static long ToLong(IReadOnlyDictionary<string, object?> row, string column)
|
||||
{
|
||||
if (row.TryGetValue(column, out var value) && value is not null)
|
||||
{
|
||||
if (value is long l) return l;
|
||||
if (value is int i) return i;
|
||||
if (value is decimal d) return (long)d;
|
||||
if (long.TryParse(value.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out long parsed))
|
||||
return parsed;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DateTime ToDateTime(IReadOnlyDictionary<string, object?> row, string column)
|
||||
{
|
||||
if (row.TryGetValue(column, out var value) && value is not null)
|
||||
{
|
||||
if (value is DateTime dt) return dt;
|
||||
if (DateTime.TryParse(value.ToString(), CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsed))
|
||||
return parsed;
|
||||
}
|
||||
return default;
|
||||
}
|
||||
Reference in New Issue
Block a user