Query Builder

TsgcHTMLComponent_QueryBuilder: een visuele query- en filterbuilder. Gebruikers combineren voorwaarden (veld, operator, waarde) in EN- en OF-groepen, met de hand of vanuit een vraag in gewone taal die de AI-assistent beantwoordt, en de server maakt er een geparametriseerde SQL-voorwaarde, een rijmatch of een filter op een Grid van, in Delphi, C++ Builder en .NET.

TsgcHTMLComponent_QueryBuilder

Voeg de velden toe die een regel kan noemen, of koppel een TsgcHTMLComponent_Grid om de kolommen ervan te gebruiken, en render hem. Elke knop verstuurt een serverevent, het component valideert de boom van dat verzoek, en OnApply geeft je de boom om je gegevens te bevragen.

Componentklasse

TsgcHTMLComponent_QueryBuilder, met TsgcHTMLQueryNode voor de boom van voorwaarden

Rendert

Een boom van voorwaarden en groepen als Bootstrap 5-markup, server-side gerenderd en zonder script

Talen

Delphi, C++ Builder, .NET

Definieer de velden, voer de regels uit op je gegevens

Fields somt op wat een regel kan noemen. OnApply ontvangt de gevalideerde boom van het verzoek, GetSQLWhere schrijft hem als SQL-voorwaarde met benoemde parameters, en ToJSON bewaart hem voor de sessie van de gebruiker.

uses
  sgcHTML_AI, sgcHTML_Component_QueryBuilder;

// Eenmalig gemaakt: het beantwoordt zijn eigen serverevents
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 is de boom van dit verzoek, Rules blijft onaangeroerd
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));      // je sessieopslag
    aResponse := DoOrdersHTML(FDQuery1);   // rijen gemarkeerd met 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 is de boom van dit verzoek
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;

Wat je gebruikers krijgen

Een filterscherm voor mensen die geen SQL schrijven, en een voorwaarde die je code veilig op elke database kan uitvoeren.

EN- en OF-groepen

Elke voorwaarde noemt een veld, een operator en één of twee waarden, en elke groep verbindt zijn kinderen met EN of OF. Groepen nesten tot MaxDepth niveaus diep en een boom bevat hoogstens MaxRules regels. Voorwaarde toevoegen en Groep toevoegen beginnen met het eerste geldende veld.

Operators per gegevenstype

Het DataType van een veld bepaalt welke operators de gebruiker kan kiezen: is gelijk aan, is niet gelijk aan, bevat, begint met, eindigt op, is groter dan, is kleiner dan, ligt tussen, is een van, is leeg en is niet leeg. Een veld met Options, een gesloten lijst met waarden, laat een kortere lijst toe.

Vraag het in gewone taal

Met een AIAssistant en AIPrompt True zet een Vragen-vak een vraag om in EN-regels over de geldende velden. De regels komen in de builder terecht, waar de gebruiker ze vóór het toepassen nog kan wijzigen, en de uitleg van het antwoord verschijnt onder het vak.

Werkt zonder API-sleutel

Een assistent zonder geconfigureerde provider antwoordt met zijn regelgebaseerde parser, zodat het Vragen-vak offline werkt. Als een aanroep van de provider mislukt, laat UseRuleBasedFallback (standaard True) dezelfde parser antwoorden.

Gekoppeld aan het Grid

Koppel een TsgcHTMLComponent_Grid en de builder neemt zijn velden over uit de gridkolommen als Fields leeg is. ApplyToGrid filtert de rijen van het grid via zijn RowFilter, en LoadFromGridOps vult een boom met één regel per filter van een gridoperatieset.

Ook voor gewone formulieren

Elk besturingselement heet <ElementName>.<path>.<key>, waarbij het pad het indexpad van het knooppunt is en de sleutel de combinator, het veld, de operator of de waarde noemt. LoadFromRequest leest die namen terug, zodat de builder ook werkt in een gewoon formulier dat zonder htmx wordt verzonden.

Belangrijkste eigenschappen, methoden en gebeurtenissen

De leden die je het vaakst gebruikt.

Fields

Fields bevat de velden die een regel kan noemen, elk met zijn Caption, DataType, SQLName en optionele Options, één waarde of value=caption per regel. Zonder items zijn de kolommen van Grid de geldende velden. FindField, GetFieldCount en IsOperatorAllowed beantwoorden vragen erover.

OnApply

OnApply(Sender, aRules, aResponse) wordt geactiveerd na Apply, Clear en een beantwoorde vraag, met de gevalideerde boom van het verzoek. Wat je in aResponse teruggeeft, wordt aan het antwoord toegevoegd, bijvoorbeeld je rijen gemarkeerd met hx-swap-oob. Zonder OnApply kopieert ApplyToGrid de boom naar Rules en filtert het gekoppelde Grid.

GetSQLWhere

Geeft de voorwaarde terug zonder het sleutelwoord WHERE, of een lege string voor een lege boom. Waarden worden alleen geschreven als de benoemde parameters :qb1, :qb2 enzovoort, elk toegevoegd aan aParams als qb1=<value>, zodat de tekst van de gebruiker de instructie niet kan wijzigen. De kolom is de SQLName van het veld, of zijn Name.

Gevalideerd, nooit vertrouwd

Alles wat een boom van buitenaf vult, JSON, een AI-antwoord of een verzonden formulier, doorloopt dezelfde validatie. Regels op velden die niet gelden, operators die het type niet toestaat, regels boven MaxRules en groepen dieper dan MaxDepth worden weggelaten, waarden worden afgekapt op 200 tekens en lege subgroepen worden verwijderd. SQLName gaat ongewijzigd de SQL in, stel hem dus in code in en nooit vanuit een verzoek.

Het JSON-formaat

ToJSON schrijft een groep als {"c":"and","r":[...]} en een regel als {"f":"field","o":"operator","v":"value"}, plus "v2" voor tussen. ParseJSON en LoadFromJSON lezen het terug en valideren het.

Matches

Matches evalueert de boom op één rij die als Name=Value-paren is opgegeven, voor rijen in het geheugen. Elke helper neemt een optionele boom, en nil betekent Rules, zodat een OnApply-handler op de boom van het verzoek werkt zonder het gedeelde component aan te raken.

Meerdere gebruikers

Eén component bedient elke sessie, omdat het serverevent op de boom van het verzoek werkt. Wijs op een pagina die door meerdere gebruikers wordt gedeeld OnApply toe, bewaar ToJSON(aRules) in de sessie en render de builder van elke gebruiker met ParseJSON en GetBuilderHTML.

Het serverevent

Elke knop, en de veld- en operatorkeuzes wanneer ze veranderen, versturen het serverevent qb naar het componenteventeindpunt van de HTMX-engine, of naar ActionURL. Het antwoord is de builder gemarkeerd met hx-swap-oob="true", die htmx vervangt op basis van zijn id: QueryBuilderID, of qb_ plus ElementName.

De demo

Demos\60.HTML\01.RunTime\25.QueryBuilder is een orderpagina op poort 8127 met de builder boven het grid en een SQL-kaart die de geparametriseerde WHERE-clausule toont die dezelfde regels op een database zouden uitvoeren. De AI-assistent heeft geen API-sleutel, dus het Vragen-vak antwoordt offline, en elke bezoeker houdt zijn eigen regels in de sessie. De designtime-, Lazarus- en .NET-versies spiegelen het.

Blijf verkennen

Online proberenBekijk het in de demo Querybouwer, live draaiend op de eSeGeCe-demoserver.
Online helpVolledige API-referentie en gebruikshandleiding voor dit component.
Grid-componentHet grid dat de builder filtert en waaruit hij zijn kolommen overneemt.
AI-assistentZet een vraag in gewone taal om in de regels van het Vragen-vak.
Alle sgcHTML-componentenBlader door de volledige functiematrix van 80+ componenten.
Download gratis proefversieDe proefversie van 30 dagen bevat de 60.HTML-demoprojecten.
PrijzenSingle-, Team- en Site-licenties met volledige broncode.
De beste deal: All-AccessElk eSeGeCe-product, inclusief Premium-ondersteuning, vanaf €1,059 per jaar.
Bekijk de All-Access-prijzen

Klaar om te beginnen?

Download de gratis proefversie en begin met het bouwen van web-UI's in Delphi, C++ Builder en .NET.