Practical patterns for integrating EgStrParser into database applications.
The most common usage: an edit field on a search form, validated on exit and applied to a query.
procedure TfrmOrders.edDateExit(Sender: TObject);
var
R: TParseResult;
begin
R := ParseInput(edDate.Text, itDate);
case R.ResultType of
otEmpty:
// No filter on this field; remove any existing WHERE clause fragment.
FDateFilter := '';
otInvalid:
begin
edDate.Color := clYellow;
Exit;
end;
else
edDate.Color := clWindow;
FDateFilter := 'OrderDate ' + R.SQLExpression;
end;
ApplyFilters;
end;R.SQLExpression for otEmpty is populated
(contains IS NULL or = ''), but the typical
application pattern is to treat empty input as “no filter” and remove
the field from the WHERE clause entirely.
Ranges are detected automatically when the input contains the range separator. No special handling is needed by the caller.
// User types: 100~500
R := ParseInput(edAmount.Text, itDecimal);
// R.ResultType = otRange
// R.SQLExpression = BETWEEN 100.0000 AND 500.0000
// User types: 2026-01-01~2026-03-31
R := ParseInput(edDate.Text, itDate);
// R.SQLExpression = BETWEEN DATE '2026-01-01' AND DATE '2026-03-31'Lists are also detected automatically.
// User types: 1001;1002;1005
R := ParseInput(edIds.Text, itInteger);
// R.ResultType = otList
// R.SQLExpression = IN (1001, 1002, 1005)
// User types: smith, jones, o'brien
R := ParseInput(edName.Text, itString, [opTrim]);
// R.SQLExpression = IN ('smith', 'jones', 'O''brien')// User types: acme
R := ParseInput(edCompany.Text, itString, [opTrim], sopLikeBoth);
// R.SQLExpression = LIKE '%acme%' ESCAPE '\'
Query1.SQL.Text := 'SELECT * FROM Companies WHERE CompanyName ' + R.SQLExpression;Configure TEgStrParser at design time (dialect, default
operator, default options) and call Parse() from event
handlers.
// In the Object Inspector:
// EgParser1.SqlDialect = sqlElevateDB
// EgParser1.DefaultOptions = [opTrim]
procedure TfrmSearch.edNameExit(Sender: TObject);
var
R: TParseResult;
begin
R := EgParser1.Parse(edName.Text, itString, sopLikeRight, Sender as TComponent);
if R.ResultType <> otInvalid then
FNameFilter := 'CustomerName ' + R.SQLExpression;
end;procedure TfrmSearch.FilterExit(Sender: TObject);
var
Ed: TEdit;
R: TParseResult;
Fragment: string;
begin
Ed := Sender as TEdit;
if Ed = edOrderDate then
R := EgParser1.Parse(Ed.Text, itDate)
else if Ed = edAmount then
R := EgParser1.Parse(Ed.Text, itDecimal)
else if Ed = edCustomer then
R := EgParser1.Parse(Ed.Text, itString, [opTrim], sopLikeBoth)
else
Exit;
Ed.Color := IfThen(R.ResultType = otInvalid, clYellow, clWindow);
if R.ResultType <> otInvalid then
FFilters.Values[Ed.Name] := R.SQLExpression;
ApplyFilters;
end;
procedure TfrmSearch.ApplyFilters;
var
Key, WhereClause: string;
Parts: TStringList;
begin
Parts := TStringList.Create;
try
for Key in FFilters.Keys do
if FFilters.Values[Key] <> '' then
Parts.Add(Key + ' ' + FFilters.Values[Key]);
WhereClause := Parts.CommaText; // or String.Join(' AND ', ...)
finally
Parts.Free;
end;
// apply to query...
end;procedure ApplyFieldFilter(const ColName, Input: string;
ValueType: TInputType; Query: TQuery);
var
R: TParseResult;
begin
R := ParseInput(Input, ValueType, [opTrim]);
case R.ResultType of
otEmpty:
// No filter: query without a WHERE clause on this column.
Query.SQL.Text := Format('SELECT * FROM T', []);
otInvalid:
raise EValidationError.CreateFmt(
'Invalid value for %s (error %d)', [ColName, R.ErrorCode]);
else
// otSingleValue, otList, otRange -- all produce a valid SQLExpression.
Query.SQL.Text :=
Format('SELECT * FROM T WHERE %s %s', [ColName, R.SQLExpression]);
end;
Query.Open;
end;Use opRequired to reject empty input and
opNotNull to reject empty list positions.
R := ParseInput(edId.Text, itInteger, [opRequired, opNotNull]);
if R.ErrorCode = ERR_EMPTY_NOT_ALLOWED then
ShowMessage('ID is required.')
else if R.ErrorCode = ERR_NULL_NOT_ALLOWED then
ShowMessage('List may not contain empty positions.')
else if R.ResultType = otInvalid then
ShowMessage('Invalid ID.')
else
// use R.SQLExpression// User types: payment invoice
R := ParseInput(edKeywords.Text, itString, [opTrim], sopContainsAll);
// sqlElevateDB: CONTAINS ALL 'payment invoice'
// other dialects: LIKE '%payment%invoice%' ESCAPE '\'
Query1.SQL.Text :=
'SELECT * FROM Documents WHERE Body ' + R.SQLExpression;function BuildFilter(const Input: string; ValueType: TInputType;
Dialect: TSqlDialect): string;
var
R: TParseResult;
begin
R := ParseInput(Input, ValueType, '~', [opTrim], sopEqual, Dialect);
if R.ResultType in [otSingleValue, otList, otRange] then
Result := R.SQLExpression
else
Result := '';
end;The parser accepts compact, ISO, and locale date formats without any configuration. Users can type in any of these and receive the same SQL output:
25/03/2026 → DATE '2026-03-25' (locale dd/mm/yyyy, pt-PT)
2026-03-25 → DATE '2026-03-25' (ISO)
25032026 → DATE '2026-03-25' (compact ddmmyyyy)
2503 → DATE '2026-03-25' (compact ddmm, current year)
No pre-processing is needed on the caller side.
Values[] contains the normalised, locale-aware display
strings. Use them to show the user what the parser understood:
R := ParseInput('25032026~31122026', itDate);
// R.Values[0]: '25-03-2026' (locale pt-PT)
// R.Values[1]: '31-12-2026'
// R.ParsedValue: '25-03-2026 ~ 31-12-2026'
lblParsed.Caption := 'Interpreted as: ' + R.ParsedValue;