Query Builder

TsgcHTMLComponent_QueryBuilder : un générateur visuel de requêtes et de filtres. Les utilisateurs combinent des conditions (champ, opérateur, valeur) dans des groupes AND et OR, à la main ou à partir d'une question en langage naturel traitée par l'AI Assistant, et le serveur transforme le résultat en une condition SQL paramétrée, une correspondance de ligne ou un filtre sur une Grid, en Delphi, C++ Builder et .NET.

TsgcHTMLComponent_QueryBuilder

Ajoutez les champs qu'une règle peut nommer, ou liez une TsgcHTMLComponent_Grid pour utiliser ses colonnes, puis rendez le composant. Chaque bouton envoie un événement serveur, le composant valide l'arbre de cette requête, et OnApply vous remet l'arbre pour interroger vos données.

Classe du composant

TsgcHTMLComponent_QueryBuilder, avec TsgcHTMLQueryNode pour l'arbre de conditions

Rendu

Un arbre de conditions et de groupes sous forme de balisage Bootstrap 5, rendu côté serveur et sans script

Langages

Delphi, C++ Builder, .NET

Définir les champs, appliquer les règles à vos données

Fields liste ce qu'une règle peut nommer. OnApply reçoit l'arbre validé de la requête, GetSQLWhere l'écrit sous forme de condition SQL avec des paramètres nommés, et ToJSON le conserve pour la session de l'utilisateur.

uses
  sgcHTML_AI, sgcHTML_Component_QueryBuilder;

// Created once: it answers its own server events
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 the tree of this request, Rules is not touched
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));      // your session store
    aResponse := DoOrdersHTML(FDQuery1);   // rows marked 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 the tree of this request
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;

Ce que vos utilisateurs obtiennent

Un écran de filtrage pour les personnes qui n'écrivent pas de SQL, et une condition que votre code peut exécuter en toute sécurité sur n'importe quelle base de données.

Groupes AND et OR

Chaque condition nomme un champ, un opérateur et une ou deux valeurs, et chaque groupe relie ses enfants par AND ou OR. Les groupes s'imbriquent jusqu'à MaxDepth niveaux et un arbre contient au plus MaxRules règles. Ajouter une condition et Ajouter un groupe commencent sur le premier champ en vigueur.

Opérateurs selon le type de données

Le DataType d'un champ détermine les opérateurs que l'utilisateur peut choisir : égal, différent, contient, commence par, finit par, supérieur, inférieur, entre, dans la liste, est vide et n'est pas vide. Un champ avec Options, une liste fermée de valeurs, autorise une liste plus courte.

Poser une question en langage naturel

Avec un AIAssistant et AIPrompt à True, une zone Ask transforme une question en règles AND sur les champs en vigueur. Les règles arrivent dans le générateur, où l'utilisateur peut encore les modifier avant de les appliquer, et l'explication de la réponse s'affiche sous la zone.

Fonctionne sans clé d'API

Un assistant sans fournisseur configuré répond avec son analyseur à base de règles, si bien que la zone Ask fonctionne hors ligne. Lorsqu'un appel au fournisseur échoue, UseRuleBasedFallback (True par défaut) laisse le même analyseur répondre.

Lié à la Grid

Liez une TsgcHTMLComponent_Grid et le générateur prend ses champs dans les colonnes de la grille lorsque Fields est vide. ApplyToGrid filtre les lignes de la grille par son RowFilter, et LoadFromGridOps remplit un arbre avec une règle par filtre d'un ensemble d'opérations de grille.

Aussi pour les formulaires simples

Chaque contrôle est nommé <ElementName>.<path>.<key>, où path est le chemin d'index du nœud et key désigne le combinateur, le champ, l'opérateur ou la valeur. LoadFromRequest relit ces noms, de sorte que le générateur fonctionne aussi dans un formulaire simple envoyé sans htmx.

Propriétés, méthodes & événements clés

Les membres que vous utiliserez le plus souvent.

Champs

Fields contient les champs qu'une règle peut nommer, chacun avec son Caption, son DataType, son SQLName et ses Options facultatives, une valeur ou value=caption par ligne. Sans éléments, les colonnes de Grid sont les champs en vigueur. FindField, GetFieldCount et IsOperatorAllowed répondent aux questions à leur sujet.

OnApply

OnApply(Sender, aRules, aResponse) se déclenche après Appliquer, Effacer et un Ask traité, avec l'arbre validé de la requête. Ce que vous renvoyez dans aResponse est ajouté à la réponse, par exemple vos lignes marquées hx-swap-oob. Sans OnApply, ApplyToGrid copie l'arbre dans Rules et filtre la Grid liée.

GetSQLWhere

Renvoie la condition sans le mot-clé WHERE, ou une chaîne vide pour un arbre vide. Les valeurs ne sont écrites que sous forme de paramètres nommés :qb1, :qb2 et ainsi de suite, chacun ajouté à aParams sous la forme qb1=<value>, de sorte que le texte de l'utilisateur ne peut pas modifier l'instruction. La colonne est le SQLName du champ, ou son Name.

Validé, jamais présumé fiable

Tout ce qui remplit un arbre depuis l'extérieur, JSON, réponse d'une IA ou formulaire envoyé, passe par la même validation. Les règles sur des champs qui ne sont pas en vigueur, les opérateurs que le type n'autorise pas, les règles au-delà de MaxRules et les groupes plus profonds que MaxDepth sont supprimés, les valeurs sont tronquées à 200 caractères et les sous-groupes vides sont retirés. SQLName entre tel quel dans le SQL : définissez-le dans le code et jamais à partir d'une requête.

Le format JSON

ToJSON écrit un groupe sous la forme {"c":"and","r":[...]} et une règle sous la forme {"f":"field","o":"operator","v":"value"}, plus "v2" pour between. ParseJSON et LoadFromJSON le relisent et le valident.

Correspondances

Matches évalue l'arbre sur une ligne donnée sous forme de paires Name=Value, pour des lignes conservées en mémoire. Chaque assistant accepte un arbre facultatif, et nil signifie Rules, de sorte qu'un gestionnaire OnApply travaille sur l'arbre de la requête sans toucher au composant partagé.

Plusieurs utilisateurs

Un composant sert toutes les sessions, car l'événement serveur travaille sur l'arbre de la requête. Sur une page partagée par plusieurs utilisateurs, affectez OnApply, conservez ToJSON(aRules) dans la session, et rendez le générateur de chaque utilisateur avec ParseJSON et GetBuilderHTML.

L'événement serveur

Chaque bouton, ainsi que les listes de champs et d'opérateurs lorsqu'ils changent, envoie l'événement serveur qb au point de terminaison des événements de composants du moteur HTMX, ou à ActionURL. La réponse est le générateur marqué hx-swap-oob="true", que htmx remplace par son id : QueryBuilderID, ou qb_ plus ElementName.

La démo

Demos\60.HTML\01.RunTime\25.QueryBuilder est une page de commandes sur le port 8127 avec le générateur au-dessus de la grille et une carte SQL qui montre la clause WHERE paramétrée que les mêmes règles exécuteraient sur une base de données. Son AI Assistant n'a pas de clé d'API, donc la zone Ask répond hors ligne, et chaque visiteur conserve ses propres règles dans la session. Les versions design time, Lazarus et .NET en sont le miroir.

Continuez l'exploration

Essayer en ligneVoyez-le dans la démo Générateur de requêtes, en fonctionnement direct sur le serveur de démos d'eSeGeCe.
Aide en ligneRéférence API complète et guide d'utilisation pour ce composant.
Composant GridLa grille que le générateur filtre et dont il reprend les colonnes.
Composant AI AssistantTransforme une question en langage naturel en règles de la zone Ask.
Tous les composants sgcHTMLParcourez la matrice complète des fonctionnalités de plus de 80 composants.
Télécharger la version d'essai gratuiteLa version d'essai de 30 jours fournit les projets de démonstration 60.HTML.
TarifsLicences Single, Team et Site avec code source complet.
Meilleur rapport qualité-prix : All-AccessTous les produits eSeGeCe, Support Premium inclus, à partir de €1,059/an.
Voir les tarifs All-Access

Prêt à démarrer ?

Téléchargez la version d'essai gratuite et commencez à créer des interfaces web en Delphi, C++ Builder et .NET.