Query Builder

TsgcHTMLComponent_QueryBuilder: wizualny konstruktor zapytań i filtrów. Użytkownicy łączą warunki (pole, operator, wartość) w grupy I oraz LUB, ręcznie albo z pytania w zwykłym języku, na które odpowiada Asystent AI, a serwer zamienia wynik na sparametryzowany warunek SQL, dopasowanie wiersza lub filtr w Grid, w Delphi, C++ Builder i .NET.

TsgcHTMLComponent_QueryBuilder

Dodaj pola, które może wskazać reguła, albo połącz TsgcHTMLComponent_Grid, aby użyć jego kolumn, i wyrenderuj komponent. Każdy przycisk wysyła zdarzenie serwera, komponent waliduje drzewo tego żądania, a OnApply przekazuje Ci drzewo do odpytania danych.

Klasa komponentu

TsgcHTMLComponent_QueryBuilder, z TsgcHTMLQueryNode dla drzewa warunków

Renderuje

Drzewo warunków i grup jako znaczniki Bootstrap 5, renderowane na serwerze i bez skryptu

Języki

Delphi, C++ Builder, .NET

Zdefiniuj pola, uruchom reguły na swoich danych

Pola wymienia to, co może wskazać reguła. OnApply otrzymuje zwalidowane drzewo żądania, GetSQLWhere zapisuje je jako warunek SQL z nazwanymi parametrami, a ToJSON zachowuje je na czas sesji użytkownika.

uses
  sgcHTML_AI, sgcHTML_Component_QueryBuilder;

// Tworzony raz: odpowiada na własne zdarzenia serwera
oQB := TsgcHTMLComponent_QueryBuilder.Create(Self);
oQB.ElementName := 'orders';
oField := oQB.Fields.Add;
oField.Name := 'customer';
oField.Caption := 'Customer';
oField := oQB.Fields.Add;
oField.Name := 'amount';
oField.Caption := 'Amount';
oField.DataType := aidtInteger;
oField.SQLName := 'o.amount';
oField := oQB.Fields.Add;
oField.Name := 'status';
oField.Caption := 'Status';
oField.Options.Add('open=Open');
oField.Options.Add('paid=Paid');
oQB.HTMXEngine := HTMXEngine1;
oQB.AIAssistant := sgcHTMLAIAssistant1;
oQB.OnApply := QueryBuilderApply;
Result := oQB.HTML;

// aRules to drzewo tego żądania, Rules pozostaje nietknięte
procedure TForm1.QueryBuilderApply(Sender: TObject;
  const aRules: TsgcHTMLQueryNode; var aResponse: string);
var
  oQB: TsgcHTMLComponent_QueryBuilder;
  oParams: TStringList;
  vWhere: string;
  i: Integer;
begin
  oQB := TsgcHTMLComponent_QueryBuilder(Sender);
  oParams := TStringList.Create;
  try
    vWhere := oQB.GetSQLWhere(oParams, aRules);
    FDQuery1.Close;
    FDQuery1.SQL.Text := 'select * from orders';
    if vWhere <> '' then
      FDQuery1.SQL.Add('where ' + vWhere);
    for i := 0 to oParams.Count - 1 do
      FDQuery1.Params.ParamByName(oParams.Names[i]).AsString :=
        oParams.ValueFromIndex[i];
    FDQuery1.Open;
    DoSaveFilter(oQB.ToJSON(aRules));      // Twój magazyn sesji
    aResponse := DoOrdersHTML(FDQuery1);   // wiersze oznaczone hx-swap-oob
  finally
    oParams.Free;
  end;
end;
// includes: sgcHTML_AI.hpp, sgcHTML_Component_QueryBuilder.hpp
oQB = new TsgcHTMLComponent_QueryBuilder(this);
oQB->ElementName = "orders";
TsgcHTMLQueryField *oField = oQB->Fields->Add();
oField->Name = "customer";
oField->Caption = "Customer";
oField = oQB->Fields->Add();
oField->Name = "amount";
oField->Caption = "Amount";
oField->DataType = aidtInteger;
oField->SQLName = "o.amount";
oQB->HTMXEngine = HTMXEngine1;
oQB->OnApply = QueryBuilderApply;
html = oQB->HTML;

void __fastcall TForm1::QueryBuilderApply(TObject *Sender,
  TsgcHTMLQueryNode* const aRules, UnicodeString &aResponse)
{
  TsgcHTMLComponent_QueryBuilder *oQB = (TsgcHTMLComponent_QueryBuilder *)Sender;
  TStringList *oParams = new TStringList();
  try
  {
    UnicodeString vWhere = oQB->GetSQLWhere(oParams, aRules);
    FDQuery1->Close();
    FDQuery1->SQL->Text = "select * from orders";
    if (vWhere != "")
      FDQuery1->SQL->Add("where " + vWhere);
    for (int i = 0; i < oParams->Count; i++)
      FDQuery1->Params->ParamByName(oParams->Names[i])->AsString =
        oParams->ValueFromIndex[i];
    FDQuery1->Open();
    DoSaveFilter(oQB->ToJSON(aRules));
    aResponse = DoOrdersHTML(FDQuery1);
  }
  __finally
  {
    delete oParams;
  }
}
using esegece.sgcWebSockets;

var qb = new TsgcHTMLComponent_QueryBuilder();
qb.ElementName = "orders";
var field = qb.Fields.Add();
field.Name = "customer";
field.Caption = "Customer";
field = qb.Fields.Add();
field.Name = "amount";
field.Caption = "Amount";
field.DataType = TsgcHTMLAIDataType.aidtInteger;
field.SQLName = "o.amount";
qb.HTMXEngine = htmxEngine;
qb.AIAssistant = aiAssistant;

// aRules to drzewo tego żądania
qb.OnApply += (object sender, TsgcHTMLQueryNode aRules, ref string aResponse) =>
{
    var parameters = new List<string>();
    string where = qb.GetSQLWhere(parameters, aRules);
    using var cmd = connection.CreateCommand();
    cmd.CommandText = "select * from orders" + (where != "" ? " where " + where : "");
    foreach (var p in parameters)
    {
        var kv = p.Split(new[] { '=' }, 2);
        cmd.Parameters.AddWithValue(":" + kv[0], kv[1]);
    }
    DoSaveFilter(qb.ToJSON(aRules));
    aResponse = DoOrdersHTML(cmd.ExecuteReader());
};

string html = qb.HTML;

Co dostają Twoi użytkownicy

Ekran filtrów dla osób, które nie piszą SQL, oraz warunek, który Twój kod może bezpiecznie uruchomić na dowolnej bazie danych.

Grupy I oraz LUB

Każdy warunek wskazuje pole, operator i jedną lub dwie wartości, a każda grupa łączy swoje elementy potomne przez I albo LUB. Grupy zagnieżdżają się do MaxDepth poziomów, a drzewo zawiera najwyżej MaxRules reguł. Dodaj warunek i Dodaj grupę zaczynają od pierwszego obowiązującego pola.

Operatory według typu danych

DataType pola decyduje, jakie operatory może wybrać użytkownik: jest równe, nie jest równe, zawiera, zaczyna się od, kończy się na, większe, mniejsze, pomiędzy, jest jednym z, jest puste i nie jest puste. Pole z Options, czyli zamkniętą listą wartości, dopuszcza krótszą listę.

Pytaj zwykłym językiem

Gdy ustawiono AIAssistant, a AIPrompt ma wartość True, pole Zapytaj zamienia pytanie na reguły I dla obowiązujących pól. Reguły trafiają do konstruktora, gdzie użytkownik może je jeszcze zmienić przed zastosowaniem, a wyjaśnienie odpowiedzi pojawia się pod polem.

Działa bez klucza API

Asystent bez skonfigurowanego dostawcy odpowiada swoim parserem opartym na regułach, więc pole Zapytaj działa offline. Gdy wywołanie dostawcy się nie powiedzie, ten sam parser odpowiada dzięki UseRuleBasedFallback (domyślnie True).

Połączony z Grid

Połącz TsgcHTMLComponent_Grid, a konstruktor weźmie pola z kolumn siatki, gdy Pola jest puste. ApplyToGrid filtruje wiersze siatki przez jej RowFilter, a LoadFromGridOps wypełnia drzewo jedną regułą na każdy filtr zestawu operacji siatki.

Także zwykłe formularze

Każda kontrolka nosi nazwę <ElementName>.<path>.<key>, gdzie ścieżka jest indeksową ścieżką węzła, a klucz wskazuje łącznik, pole, operator lub wartość. LoadFromRequest odczytuje te nazwy z powrotem, więc konstruktor działa też w zwykłym formularzu wysyłanym bez htmx.

Kluczowe właściwości, metody i zdarzenia

Składowe, po które sięgasz najczęściej.

Pola

Pola zawiera pola, które może wskazać reguła, każde z Caption, DataType, SQLName i opcjonalnymi Options, jedna wartość lub value=caption w wierszu. Bez elementów polami obowiązującymi są kolumny Grid. FindField, GetFieldCount i IsOperatorAllowed odpowiadają na pytania o nie.

OnApply

OnApply(Sender, aRules, aResponse) uruchamia się po Zastosuj, Wyczyść i po udzielonej odpowiedzi na Zapytaj, ze zwalidowanym drzewem żądania. To, co zwrócisz w aResponse, jest dołączane do odpowiedzi, na przykład Twoje wiersze oznaczone hx-swap-oob. Bez OnApply metoda ApplyToGrid kopiuje drzewo do Rules i filtruje połączony Grid.

GetSQLWhere

Zwraca warunek bez słowa kluczowego WHERE, a dla pustego drzewa pusty ciąg. Wartości są zapisywane wyłącznie jako nazwane parametry :qb1, :qb2 i tak dalej, każdy dodany do aParams jako qb1=<value>, więc tekst użytkownika nie może zmienić instrukcji. Kolumną jest SQLName pola albo jego Name.

Zwalidowane, nigdy nie zaufane

Wszystko, co wypełnia drzewo z zewnątrz, czyli JSON, odpowiedź AI lub wysłany formularz, przechodzi tę samą walidację. Reguły dla pól, które nie obowiązują, operatory niedozwolone dla typu, reguły ponad MaxRules i grupy głębsze niż MaxDepth są odrzucane, wartości są przycinane do 200 znaków, a puste podgrupy usuwane. SQLName trafia do SQL bez zmian, więc ustawiaj go w kodzie, nigdy na podstawie żądania.

Format JSON

ToJSON zapisuje grupę jako {"c":"and","r":[...]}, a regułę jako {"f":"field","o":"operator","v":"value"}, a dla between dodatkowo "v2". ParseJSON i LoadFromJSON odczytują go z powrotem i walidują.

Matches

Matches ocenia drzewo na jednym wierszu podanym jako pary Name=Value, dla wierszy przechowywanych w pamięci. Każda metoda pomocnicza przyjmuje opcjonalne drzewo, a nil oznacza Rules, więc procedura OnApply pracuje na drzewie żądania bez dotykania współdzielonego komponentu.

Wielu użytkowników

Jeden komponent obsługuje każdą sesję, ponieważ zdarzenie serwera działa na drzewie żądania. Na stronie współdzielonej przez wielu użytkowników przypisz OnApply, przechowuj ToJSON(aRules) w sesji i renderuj konstruktor każdego użytkownika przez ParseJSON i GetBuilderHTML.

Zdarzenie serwera

Każdy przycisk oraz listy pól i operatorów po zmianie wysyłają zdarzenie serwera qb do punktu końcowego zdarzeń komponentów silnika HTMX albo do ActionURL. Odpowiedzią jest konstruktor oznaczony hx-swap-oob="true", który htmx podmienia według jego identyfikatora: QueryBuilderID albo qb_ plus ElementName.

Demo

Demos\60.HTML\01.RunTime\25.QueryBuilder to strona zamówień na porcie 8127 z konstruktorem nad siatką i kartą SQL, która pokazuje sparametryzowaną klauzulę WHERE, jaką te same reguły uruchomiłyby w bazie danych. Jego Asystent AI nie ma klucza API, więc pole Zapytaj odpowiada offline, a każdy odwiedzający zachowuje własne reguły w sesji. Wersje design time, Lazarus i .NET są jego odpowiednikami.

Odkrywaj dalej

Wypróbuj onlineZobacz to w demie Kreator zapytań, działającym na żywo na serwerze demo eSeGeCe.
Pomoc onlinePełna dokumentacja API i przewodnik użytkowania tego komponentu.
Komponent GridSiatka, którą konstruktor filtruje i z której bierze kolumny.
Asystent AIZamienia pytanie w zwykłym języku na reguły pola Zapytaj.
Wszystkie komponenty sgcHTMLPrzejrzyj pełną matrycę funkcji 80+ komponentów.
Pobierz bezpłatną wersję próbną30-dniowa wersja próbna zawiera projekty demonstracyjne 60.HTML.
CennikLicencje Single, Team i Site z pełnym kodem źródłowym.
Najkorzystniejsza oferta: All-AccessWszystkie produkty eSeGeCe, ze wsparciem Premium w cenie, już od €1,059 rocznie.
Zobacz cennik All-Access

Gotowy, aby zacząć?

Pobierz bezpłatną wersję próbną i zacznij budować interfejsy webowe w Delphi, C++ Builder i .NET.