FreeGrid .NET server helper
===========================

FreeGridQuery.cs   one file (namespace FreeGrid), .NET 8+, System.Text.Json and ADO.NET only

  GridRequest.From(body)   reads restDatasource's request (paging, sort, filters, quick filter, advanced filter, grouping)
  FreeGridQuery.Build(r)   turns it into SQL: Where, OrderBy, Page, Parameters (@p0, @p1...), CountParameters, Group
  GridRows.Read(reader)    rows for the { rows, total } response, dates as "YYYY-MM-DD"
  GridSave.From(body)      { created, updated, deleted } from saveChanges()

  var query = new FreeGridQuery()
      .Column("orderNo", "ORDER_NO", ColumnType.Text)
      .Column("qty", "QTY", ColumnType.Number)
      .UseDialect(Dialect.Standard)    // SQL Server; Dialect.Limit for SQLite, MySQL, PostgreSQL
      .DefaultOrderBy("ID");
  var sql = query.Build(GridRequest.From(body));
  cmd.CommandText = "SELECT ... FROM ORDERS" + sql.Where + sql.OrderBy + sql.Page;
  sql.AddParameters(cmd);              // Dapper: new DynamicParameters(sql.Parameters)

Works with Microsoft.Data.SqlClient, Microsoft.Data.Sqlite, Npgsql and MySqlConnector.

Only the columns you list can be sorted, filtered or grouped; every value is a bound parameter.
A bad number or date, an unknown filter op or too many values raises GridError: answer 400 { message }.
LIKE searches use ESCAPE '!', so % and _ typed in a filter are matched as text.

What the grid sends and what to answer, with a full example server:
  https://freegrid.app/docs/server/     (English)
  https://freegrid.app/ko/docs/server/  (한국어)

Use is covered by the FreeGrid license: https://freegrid.app/pricing/
