From 9a839e67abc2a56c494fbe1425050119d037635b Mon Sep 17 00:00:00 2001 From: AishwaryaRameshbabu-SF3446 Date: Fri, 13 Mar 2026 18:39:12 +0530 Subject: [PATCH] 1015702-MySQL-stored-procedure-content --- .../Grid_MySQL.Server/CHANGELOG.md | 8 + .../Controllers/GridController.cs | 135 ++++++++++++++ .../Data/AppDataConnection.cs | 147 +++++++++++++++ .../Data/SqlClauseBuilder.cs | 175 ++++++++++++++++++ .../Grid_MySQL.Server.csproj | 26 +++ .../Grid_MySQL.Server.csproj.user | 6 + .../Grid_MySQL.Server/Grid_MySQL.Server.http | 6 + .../Grid_MySQL.Server/Models/Transaction.cs | 47 +++++ .../Grid_MySQL.Server/Program.cs | 34 ++++ .../Properties/launchSettings.json | 45 +++++ .../appsettings.Development.json | 8 + .../Grid_MySQL.Server/appsettings.json | 12 ++ .../Grid_MySQL.sln | 33 ++++ .../grid_mysql.client/CHANGELOG.md | 16 ++ .../grid_mysql.client/README.md | 73 ++++++++ .../grid_mysql.client/aspnetcore-https.js | 37 ++++ .../grid_mysql.client/eslint.config.js | 23 +++ .../grid_mysql.client.esproj | 10 + .../grid_mysql.client/index.html | 14 ++ .../grid_mysql.client/package.json | 33 ++++ .../grid_mysql.client/public/vite.svg | 1 + .../grid_mysql.client/src/App.css | 1 + .../grid_mysql.client/src/App.tsx | 59 ++++++ .../grid_mysql.client/src/CustomAdaptor.ts | 69 +++++++ .../grid_mysql.client/src/assets/react.svg | 1 + .../grid_mysql.client/src/index.css | 10 + .../grid_mysql.client/src/main.tsx | 10 + .../grid_mysql.client/tsconfig.app.json | 28 +++ .../grid_mysql.client/tsconfig.json | 7 + .../grid_mysql.client/tsconfig.node.json | 26 +++ .../grid_mysql.client/vite.config.ts | 61 ++++++ 31 files changed, 1161 insertions(+) create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/CHANGELOG.md create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Controllers/GridController.cs create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Data/AppDataConnection.cs create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Data/SqlClauseBuilder.cs create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.csproj create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.csproj.user create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.http create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Models/Transaction.cs create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Program.cs create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Properties/launchSettings.json create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/appsettings.Development.json create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/appsettings.json create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.sln create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/CHANGELOG.md create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/README.md create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/aspnetcore-https.js create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/eslint.config.js create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/grid_mysql.client.esproj create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/index.html create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/package.json create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/public/vite.svg create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/App.css create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/App.tsx create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/CustomAdaptor.ts create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/assets/react.svg create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/index.css create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/main.tsx create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.app.json create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.json create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.node.json create mode 100644 connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/vite.config.ts diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/CHANGELOG.md b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/CHANGELOG.md new file mode 100644 index 0000000..03c2619 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/CHANGELOG.md @@ -0,0 +1,8 @@ +This file explains how Visual Studio created the project. + +The following steps were used to generate this project: +- Create new ASP\.NET Core Web API project. +- Update project file to add a reference to the frontend project and set SPA properties. +- Update `launchSettings.json` to register the SPA proxy as a startup assembly. +- Add project to the startup projects list. +- Write this file. diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Controllers/GridController.cs b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Controllers/GridController.cs new file mode 100644 index 0000000..96d8ec5 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Controllers/GridController.cs @@ -0,0 +1,135 @@ +using Grid_MySQL.Server.Data; +using Grid_MySQL.Server.Models; +using Microsoft.AspNetCore.Mvc; +using Syncfusion.EJ2.Base; + +namespace Grid_MySQL.Server.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class GridController(AppDataConnection db) : ControllerBase + { + private readonly AppDataConnection _db = db; + + // POST: /api/grid/url + // All data actions (search, filter, multi-column sort, paging) are delegated to sp_GetTransactions via pre-built MySQL clause strings. + [HttpPost("url")] + public async Task UrlDatasource([FromBody] DataManagerRequest dm) + { + // Translate Syncfusion DataManagerRequest into MySQL clause strings using SqlClauseBuilder. + + var searchClause = SqlClauseBuilder.BuildSearchClause(dm.Search); + var whereClause = SqlClauseBuilder.BuildWhereClause(dm.Where); + var sortClause = SqlClauseBuilder.BuildSortClause(dm.Sorted); + + // Call the stored procedure. + var result = await _db.SpGetTransactionsAsync( + searchClause: searchClause, + whereClause: whereClause, + sortClause: sortClause, + skip: dm.Skip, + take: dm.Take + ); + + // Return the response + if (dm.RequiresCounts) + return Ok(new { result = result.Rows, count = result.TotalCount }); + + return Ok(result.Rows); + } + + // POST: /api/grid/insert + // Delegates to sp_InsertTransaction and returns the new row with its generated Id. + [HttpPost("insert")] + public async Task Insert([FromBody] CRUDModel model) + { + if (model?.Value == null) + return BadRequest(); + + var value = model.Value; + + // Ensure CreatedAt is set before insert. + if (value.CreatedAt == default) + value.CreatedAt = DateTime.UtcNow; + + // Call stored procedure; it sets the OUT param and returns the new Id. + var newId = await _db.SpInsertTransactionAsync(value); + value.Id = newId; + + return Ok(value); + } + + // POST: /api/grid/update + // Delegates to sp_UpdateTransaction. Returns 404 when the row is not found. + [HttpPost("update")] + public async Task Update([FromBody] CRUDModel model) + { + if (model?.Value == null) + return BadRequest(); + + var value = model.Value; + + // Call stored procedure; it returns the number of affected rows. + var affected = await _db.SpUpdateTransactionAsync(value); + if (affected == 0) + return NotFound("Record not found"); + + return Ok(value); + } + + // POST: /api/grid/remove + // Delegates to sp_DeleteTransaction. Returns 404 when the row is not found. + [HttpPost("remove")] + public async Task Remove([FromBody] CRUDModel model) + { + var key = Convert.ToInt32(model.Key); + + // Call stored procedure; it returns the number of affected rows. + var affected = await _db.SpDeleteTransactionAsync(key); + if (affected == 0) + return NotFound("Record not found"); + + return Ok(new { key }); + } + + // POST: /api/grid/batch + // Handles batch add / update / delete in a single DB transaction, + // each operation routed through the relevant stored procedure. + [HttpPost("batch")] + public async Task BatchUpdate([FromBody] CRUDModel payload) + { + using var tr = await _db.BeginTransactionAsync(); + + // INSERT many – sp_InsertTransaction is called once per added row. + if (payload.Added != null && payload.Added.Count > 0) + { + foreach (var r in payload.Added) + { + if (r.CreatedAt == default) + r.CreatedAt = DateTime.UtcNow; + + var newId = await _db.SpInsertTransactionAsync(r); + r.Id = newId; // echo generated key back to the client + } + } + + // UPDATE many – sp_UpdateTransaction is called once per changed row. + if (payload.Changed != null && payload.Changed.Count > 0) + { + foreach (var r in payload.Changed) + await _db.SpUpdateTransactionAsync(r); + } + + // DELETE many – sp_DeleteTransaction is called once per deleted row. + if (payload.Deleted != null && payload.Deleted.Count > 0) + { + foreach (var r in payload.Deleted) + if (r.Id.HasValue) + await _db.SpDeleteTransactionAsync(r.Id.Value); + } + + await tr.CommitAsync(); + return Ok(payload); + } + } +} diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Data/AppDataConnection.cs b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Data/AppDataConnection.cs new file mode 100644 index 0000000..ccfdca6 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Data/AppDataConnection.cs @@ -0,0 +1,147 @@ +using Grid_MySQL.Server.Models; +using LinqToDB; +using LinqToDB.Data; +using LinqToDB.DataProvider.MySql; + +namespace Grid_MySQL.Server.Data +{ + // Holds the paged rows and the total matching count returned by sp_GetTransactions + public sealed class PagedResult + { + public List Rows { get; init; } = []; + public int TotalCount { get; init; } + } + + public sealed class AppDataConnection : DataConnection + { + public AppDataConnection(IConfiguration config) + : base( + new DataOptions().UseMySql( + config.GetConnectionString("MySqlConn")!, + MySqlVersion.MySql80, + MySqlProvider.MySqlConnector + ) + ) + { + InlineParameters = true; + } + + // Direct table access + public ITable Transactions => this.GetTable(); + + // ------------------------------------------------------------------ + // Stored-procedure helpers + // ------------------------------------------------------------------ + + // Calls sp_GetTransactions with all data-action parameters so that sorting, filtering, + // searching, and paging are executed entirely inside MySQL. + + public async Task SpGetTransactionsAsync( + string? searchClause, + string? whereClause, + string? sortClause, + int skip, + int take) + { + // OUT parameter – MySQL writes the total count into it. + var outCount = new DataParameter("p_TotalCount", null, LinqToDB.DataType.Int32) + { + Direction = System.Data.ParameterDirection.Output + }; + + // sp_GetTransactions returns one result set (the paged rows) and + // sets the OUT parameter p_TotalCount. + var rows = await this.QueryProcAsync( + "sp_GetTransactions", + new DataParameter("p_SearchClause", searchClause ?? string.Empty, LinqToDB.DataType.NVarChar), + new DataParameter("p_WhereClause", whereClause ?? string.Empty, LinqToDB.DataType.NVarChar), + new DataParameter("p_SortClause", sortClause ?? string.Empty, LinqToDB.DataType.NVarChar), + new DataParameter("p_Skip", skip, LinqToDB.DataType.Int32), + new DataParameter("p_Take", take, LinqToDB.DataType.Int32), + outCount + ); + + return new PagedResult + { + Rows = rows.ToList(), + TotalCount = Convert.ToInt32(outCount.Value) + }; + } + + + // Calls sp_InsertTransaction, captures the OUT parameter p_NewId, and returns the newly generated auto-increment Id. + public async Task SpInsertTransactionAsync(Transaction t) + { + // The OUT parameter must be declared as a DataParameter with + // Direction = Output so LinqToDB reads back the value MySQL sets. + var outId = new DataParameter("p_NewId", null, LinqToDB.DataType.Int32) + { + Direction = System.Data.ParameterDirection.Output + }; + + await this.ExecuteProcAsync( + "sp_InsertTransaction", + new DataParameter("p_TransactionId", t.TransactionId, LinqToDB.DataType.NVarChar), + new DataParameter("p_CustomerId", t.CustomerId, LinqToDB.DataType.Int32), + new DataParameter("p_OrderId", t.OrderId, LinqToDB.DataType.Int32), + new DataParameter("p_InvoiceNumber", t.InvoiceNumber, LinqToDB.DataType.NVarChar), + new DataParameter("p_Description", t.Description, LinqToDB.DataType.NVarChar), + new DataParameter("p_Amount", t.Amount, LinqToDB.DataType.Decimal), + new DataParameter("p_CurrencyCode", t.CurrencyCode, LinqToDB.DataType.NVarChar), + new DataParameter("p_TransactionType", t.TransactionType, LinqToDB.DataType.NVarChar), + new DataParameter("p_PaymentGateway", t.PaymentGateway, LinqToDB.DataType.NVarChar), + new DataParameter("p_CreatedAt", t.CreatedAt, LinqToDB.DataType.DateTime), + new DataParameter("p_CompletedAt", t.CompletedAt, LinqToDB.DataType.DateTime), + new DataParameter("p_Status", t.Status, LinqToDB.DataType.NVarChar), + outId + ); + + return Convert.ToInt32(outId.Value); + } + + + // Calls sp_UpdateTransaction for the given transaction row. Returns the number of rows affected (0 = not found, 1 = updated). + public async Task SpUpdateTransactionAsync(Transaction t) + { + // sp_UpdateTransaction returns a single-row result set containing + // AffectedRows. Use QueryProcAsync to read that result set. + var rows = await this.QueryProcAsync( + "sp_UpdateTransaction", + new DataParameter("p_Id", t.Id, LinqToDB.DataType.Int32), + new DataParameter("p_TransactionId", t.TransactionId, LinqToDB.DataType.NVarChar), + new DataParameter("p_CustomerId", t.CustomerId, LinqToDB.DataType.Int32), + new DataParameter("p_OrderId", t.OrderId, LinqToDB.DataType.Int32), + new DataParameter("p_InvoiceNumber", t.InvoiceNumber, LinqToDB.DataType.NVarChar), + new DataParameter("p_Description", t.Description, LinqToDB.DataType.NVarChar), + new DataParameter("p_Amount", t.Amount, LinqToDB.DataType.Decimal), + new DataParameter("p_CurrencyCode", t.CurrencyCode, LinqToDB.DataType.NVarChar), + new DataParameter("p_TransactionType", t.TransactionType, LinqToDB.DataType.NVarChar), + new DataParameter("p_PaymentGateway", t.PaymentGateway, LinqToDB.DataType.NVarChar), + new DataParameter("p_CreatedAt", t.CreatedAt, LinqToDB.DataType.DateTime), + new DataParameter("p_CompletedAt", t.CompletedAt, LinqToDB.DataType.DateTime), + new DataParameter("p_Status", t.Status, LinqToDB.DataType.NVarChar) + ); + + return rows.FirstOrDefault()?.AffectedRows ?? 0; + } + + + // Calls sp_DeleteTransaction for the given primary key. Returns the number of rows deleted (0 = not found, 1 = deleted). + public async Task SpDeleteTransactionAsync(int id) + { + var rows = await this.QueryProcAsync( + "sp_DeleteTransaction", + new DataParameter("p_Id", id, LinqToDB.DataType.Int32) + ); + + return rows.FirstOrDefault()?.AffectedRows ?? 0; + } + } + + // Small DTO used to map the AffectedRows result-set column that + // sp_UpdateTransaction and sp_DeleteTransaction return. + internal sealed class AffectedRowsResult + { + public int AffectedRows { get; set; } + } +} diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Data/SqlClauseBuilder.cs b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Data/SqlClauseBuilder.cs new file mode 100644 index 0000000..27adfea --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Data/SqlClauseBuilder.cs @@ -0,0 +1,175 @@ +using Syncfusion.EJ2.Base; + +namespace Grid_MySQL.Server.Data +{ + // Builds MySQL-safe SQL clause strings from Syncfusion DataManagerRequest + public static class SqlClauseBuilder + { + // Allowed column names + private static readonly HashSet AllowedColumns = new(StringComparer.OrdinalIgnoreCase) + { + "Id", "TransactionId", "CustomerId", "OrderId", "InvoiceNumber", + "Description", "Amount", "CurrencyCode", "TransactionType", + "PaymentGateway", "CreatedAt", "CompletedAt", "Status" + }; + + // Builds the body of a WHERE clause for searching + public static string? BuildSearchClause(List? searches) + { + if (searches == null || searches.Count == 0) + return null; + + var andBlocks = new List(); + + foreach (var s in searches) + { + if (string.IsNullOrWhiteSpace(s.Key)) + continue; + IEnumerable cols = (s.Fields != null && s.Fields.Count > 0) + ? s.Fields.Where(f => AllowedColumns.Contains(f)) + : AllowedColumns; + + var safeKey = EscapeLike(s.Key); + var orParts = cols.Select(col => $"`{col}` LIKE '%{safeKey}%'").ToList(); + + if (orParts.Count > 0) + andBlocks.Add($"({string.Join(" OR ", orParts)})"); + } + + return andBlocks.Count > 0 ? string.Join(" AND ", andBlocks) : null; + } + + // Builds the body of a WHERE clause for filtering + public static string? BuildWhereClause(List? filters) + { + if (filters == null || filters.Count == 0) + return null; + + var parts = filters + .Select(BuildSingleFilter) + .Where(s => s != null) + .ToList(); + + if (parts.Count == 0) + return null; + + return string.Join(" AND ", parts); + } + + + // Builds the body of an ORDER BY clause from the Syncfusion Sorted list. + public static string? BuildSortClause(List? sorts) + { + if (sorts == null || sorts.Count == 0) + return null; + + var parts = new List(); + + foreach (var s in sorts) + { + if (!AllowedColumns.Contains(s.Name)) + continue; + + var dir = string.Equals(s.Direction, "descending", StringComparison.OrdinalIgnoreCase) + ? "DESC" + : "ASC"; + + parts.Add($"`{s.Name}` {dir}"); + } + + return parts.Count > 0 ? string.Join(", ", parts) : null; + } + + // Recursively converts a single WhereFilter (or a group of nested WhereFilters) into a MySQL expression string. + + private static string? BuildSingleFilter(WhereFilter f) + { + // ---- Nested predicate group ---- + if (f.predicates != null && f.predicates.Count > 0) + { + var subParts = f.predicates + .Select(BuildSingleFilter) + .Where(s => s != null) + .ToList(); + + if (subParts.Count == 0) + return null; + + var joiner = string.Equals(f.Condition, "or", StringComparison.OrdinalIgnoreCase) + ? " OR " + : " AND "; + + return $"({string.Join(joiner, subParts)})"; + } + + // ---- Leaf predicate ---- + if (string.IsNullOrWhiteSpace(f.Field) || !AllowedColumns.Contains(f.Field)) + return null; + + var col = $"`{f.Field}`"; + var op = (f.Operator ?? "equal").ToLowerInvariant(); + + // NULL checks + if (op == "isnull") return $"{col} IS NULL"; + if (op == "isnotnull") return $"{col} IS NOT NULL"; + if (op == "isempty") return $"{col} = ''"; + if (op == "isnotempty") return $"{col} != ''"; + + if (f.value == null) + return null; + + return op switch + { + "equal" => $"{col} = {SqlValue(f.Field, f.value)}", + "notequal" => $"{col} != {SqlValue(f.Field, f.value)}", + "lessthan" => $"{col} < {SqlValue(f.Field, f.value)}", + "lessthanorequal" => $"{col} <= {SqlValue(f.Field, f.value)}", + "greaterthan" => $"{col} > {SqlValue(f.Field, f.value)}", + "greaterthanorequal" => $"{col} >= {SqlValue(f.Field, f.value)}", + "contains" => $"{col} LIKE '%{EscapeLike(f.value.ToString()!)}%'", + "doesnotcontain" => $"{col} NOT LIKE '%{EscapeLike(f.value.ToString()!)}%'", + "startswith" => $"{col} LIKE '{EscapeLike(f.value.ToString()!)}%'", + "endswith" => $"{col} LIKE '%{EscapeLike(f.value.ToString()!)}'", + _ => null + }; + } + + // Returns a MySQL-literal for the given field value. + private static string SqlValue(string field, object value) + { + // Numeric columns + if (IsNumericColumn(field)) + { + if (decimal.TryParse(value.ToString(), System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, out var n)) + return n.ToString(System.Globalization.CultureInfo.InvariantCulture); + } + + // DateTime columns + if (IsDateColumn(field)) + { + if (DateTime.TryParse(value.ToString(), + System.Globalization.CultureInfo.InvariantCulture, + System.Globalization.DateTimeStyles.None, out var dt)) + return $"'{dt:yyyy-MM-dd HH:mm:ss}'"; + } + + // Default: single-quoted string with SQL injection prevention + return $"'{EscapeString(value.ToString()!)}'"; + } + + private static bool IsNumericColumn(string field) => + field is "Id" or "CustomerId" or "OrderId" or "Amount"; + + private static bool IsDateColumn(string field) => + field is "CreatedAt" or "CompletedAt"; + + // Escapes single quotes and backslashes for a MySQL string literal + private static string EscapeString(string s) => + s.Replace("\\", "\\\\").Replace("'", "\\'"); + + // Escapes LIKE meta-characters (%, _) plus the usual string escapes + private static string EscapeLike(string s) => + EscapeString(s).Replace("%", "\\%").Replace("_", "\\_"); + } +} diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.csproj b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.csproj new file mode 100644 index 0000000..47a34d1 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.csproj @@ -0,0 +1,26 @@ + + + net10.0 + enable + ..\grid_mysql.client + npm start + https://localhost:62268 + + + + + + + + 10.*-* + + + + + + + + false + + + diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.csproj.user b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.csproj.user new file mode 100644 index 0000000..9ff5820 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.csproj.user @@ -0,0 +1,6 @@ + + + + https + + \ No newline at end of file diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.http b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.http new file mode 100644 index 0000000..ed2fa56 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Grid_MySQL.Server.http @@ -0,0 +1,6 @@ +@Grid_MySQL.Server_HostAddress = http://localhost:5283 + +GET {{Grid_MySQL.Server_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Models/Transaction.cs b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Models/Transaction.cs new file mode 100644 index 0000000..ce2e877 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Models/Transaction.cs @@ -0,0 +1,47 @@ +using LinqToDB.Mapping; + +namespace Grid_MySQL.Server.Models +{ + [Table("transactions")] + public class Transaction + { + [PrimaryKey, Identity] + public int? Id { get; set; } + + [Column, NotNull] + public string TransactionId { get; set; } + + [Column, NotNull] + public int CustomerId { get; set; } + + [Column] + public int? OrderId { get; set; } + + [Column] + public string InvoiceNumber { get; set; } + + [Column] + public string Description { get; set; } + + [Column, NotNull] + public decimal Amount { get; set; } + + [Column] + public string CurrencyCode { get; set; } + + [Column] + public string TransactionType { get; set; } + + [Column] + public string PaymentGateway { get; set; } + + [Column, NotNull] + public DateTime CreatedAt { get; set; } + + [Column] + public DateTime? CompletedAt { get; set; } + + [Column] + public string Status { get; set; } + } +} diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Program.cs b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Program.cs new file mode 100644 index 0000000..8dc6b1c --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Program.cs @@ -0,0 +1,34 @@ +using Grid_MySQL.Server.Data; +using LinqToDB; +using LinqToDB.AspNet; +using LinqToDB.DataProvider.MySql; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllers().AddNewtonsoftJson(); + +// CORS (dev) +builder.Services.AddCors(options => +{ + options.AddPolicy("cors", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()); +}); + +// 1) Register LinqToDB engine (connection factory) with MySQL provider +builder.Services.AddLinqToDB( + (sp, options) => + options.UseMySql( + builder.Configuration.GetConnectionString("MySqlConn"), + MySqlVersion.MySql80, + MySqlProvider.MySqlConnector + ) +); + +// 2) Register your typed DataConnection so controllers can inject it +builder.Services.AddScoped(); + +var app = builder.Build(); + +app.UseCors("cors"); +app.MapControllers(); + +app.Run(); diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Properties/launchSettings.json b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Properties/launchSettings.json new file mode 100644 index 0000000..05db172 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/Properties/launchSettings.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:27953", + "sslPort": 44349 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5283", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7143;http://localhost:5283", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy" + } + } + } +} + diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/appsettings.Development.json b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/appsettings.json b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/appsettings.json new file mode 100644 index 0000000..2aea09e --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.Server/appsettings.json @@ -0,0 +1,12 @@ +{ + "ConnectionStrings": { + "MySqlConn": "Server=localhost;Port=3306;Database=transactiondb;User Id=root;Password=Syncfusion@123;SslMode=None;" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.sln b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.sln new file mode 100644 index 0000000..9060b8b --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/Grid_MySQL.sln @@ -0,0 +1,33 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36811.4 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "grid_mysql.client", "grid_mysql.client\grid_mysql.client.esproj", "{BFE7B104-8353-2AD3-8556-CB3C9C813E26}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grid_MySQL.Server", "Grid_MySQL.Server\Grid_MySQL.Server.csproj", "{C91B9C7F-EC75-48B6-9129-AD12D77BEF98}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BFE7B104-8353-2AD3-8556-CB3C9C813E26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BFE7B104-8353-2AD3-8556-CB3C9C813E26}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BFE7B104-8353-2AD3-8556-CB3C9C813E26}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {BFE7B104-8353-2AD3-8556-CB3C9C813E26}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BFE7B104-8353-2AD3-8556-CB3C9C813E26}.Release|Any CPU.Build.0 = Release|Any CPU + {BFE7B104-8353-2AD3-8556-CB3C9C813E26}.Release|Any CPU.Deploy.0 = Release|Any CPU + {C91B9C7F-EC75-48B6-9129-AD12D77BEF98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C91B9C7F-EC75-48B6-9129-AD12D77BEF98}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C91B9C7F-EC75-48B6-9129-AD12D77BEF98}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C91B9C7F-EC75-48B6-9129-AD12D77BEF98}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4A0ABFC4-7856-4155-ADD4-D9E4D323A329} + EndGlobalSection +EndGlobal diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/CHANGELOG.md b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/CHANGELOG.md new file mode 100644 index 0000000..2b235fc --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/CHANGELOG.md @@ -0,0 +1,16 @@ +This file explains how Visual Studio created the project. + +The following tools were used to generate this project: +- create-vite + +The following steps were used to generate this project: +- Create react project with create-vite: `npm init --yes vite@latest ticketmanagement.client -- --template=react-ts`. +- Update `vite.config.ts` to set up proxying and certs. +- Add `@type/node` for `vite.config.js` typing. +- Update `App` component to fetch and display weather information. +- Create project file (`ticketmanagement.client.esproj`). +- Create `launch.json` to enable debugging. +- Add project to solution. +- Update proxy endpoint to be the backend server endpoint. +- Add project to the startup projects list. +- Write this file. diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/README.md b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/README.md new file mode 100644 index 0000000..d2e7761 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/README.md @@ -0,0 +1,73 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## React Compiler + +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: + +```js +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + + // Remove tseslint.configs.recommended and replace with this + tseslint.configs.recommendedTypeChecked, + // Alternatively, use this for stricter rules + tseslint.configs.strictTypeChecked, + // Optionally, add this for stylistic rules + tseslint.configs.stylisticTypeChecked, + + // Other configs... + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` + +You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: + +```js +// eslint.config.js +import reactX from 'eslint-plugin-react-x' +import reactDom from 'eslint-plugin-react-dom' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + // Enable lint rules for React + reactX.configs['recommended-typescript'], + // Enable lint rules for React DOM + reactDom.configs.recommended, + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/aspnetcore-https.js b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/aspnetcore-https.js new file mode 100644 index 0000000..cab03ec --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/aspnetcore-https.js @@ -0,0 +1,37 @@ +// This script sets up HTTPS for the application using the ASP.NET Core HTTPS certificate +const fs = require('fs'); +const spawn = require('child_process').spawn; +const path = require('path'); + +const baseFolder = + process.env.APPDATA !== undefined && process.env.APPDATA !== '' + ? `${process.env.APPDATA}/ASP.NET/https` + : `${process.env.HOME}/.aspnet/https`; + +const certificateArg = process.argv.map(arg => arg.match(/--name=(?.+)/i)).filter(Boolean)[0]; +const certificateName = certificateArg ? certificateArg.groups.value : process.env.npm_package_name; + +if (!certificateName) { + console.error('Invalid certificate name. Run this script in the context of an npm/yarn script or pass --name=<> explicitly.') + process.exit(-1); +} + +const certFilePath = path.join(baseFolder, `${certificateName}.pem`); +const keyFilePath = path.join(baseFolder, `${certificateName}.key`); + +if (!fs.existsSync(baseFolder)) { + fs.mkdirSync(baseFolder, { recursive: true }); +} + +if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) { + spawn('dotnet', [ + 'dev-certs', + 'https', + '--export-path', + certFilePath, + '--format', + 'Pem', + '--no-password', + ], { stdio: 'inherit', }) + .on('exit', (code) => process.exit(code)); +} \ No newline at end of file diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/eslint.config.js b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/eslint.config.js new file mode 100644 index 0000000..5e6b472 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/eslint.config.js @@ -0,0 +1,23 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]) diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/grid_mysql.client.esproj b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/grid_mysql.client.esproj new file mode 100644 index 0000000..06f55e3 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/grid_mysql.client.esproj @@ -0,0 +1,10 @@ + + + npm start + Jasmine + + false + + $(MSBuildProjectDirectory)\dist\grid_mysql.client\ + + \ No newline at end of file diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/index.html b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/index.html new file mode 100644 index 0000000..28d0c05 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/index.html @@ -0,0 +1,14 @@ + + + + + + + GridMysqlClient + + + +
+ + + diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/package.json b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/package.json new file mode 100644 index 0000000..f6a7fdd --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/package.json @@ -0,0 +1,33 @@ +{ + "name": "ticketmanagement.client", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite", + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@syncfusion/ej2-data": "^32.1.24", + "@syncfusion/ej2-react-grids": "^32.1.25", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/node": "^24.10.1", + "@types/react": "^19.2.5", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.4", + "vite": "^7.2.4" + } +} diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/public/vite.svg b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/App.css b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/App.css new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/App.css @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/App.tsx b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/App.tsx new file mode 100644 index 0000000..54b4338 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/App.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import { + GridComponent, ColumnsDirective, ColumnDirective, Inject, Edit, Toolbar, Page, Sort, Filter, Search, + type FilterSettingsModel, type EditSettingsModel, type ToolbarItems, +} from '@syncfusion/ej2-react-grids'; +import { DataManager } from '@syncfusion/ej2-data'; +import { CustomAdaptor } from './CustomAdaptor'; + +const App: React.FC = () => { + const dateDefault = new Date(); + const transactionIdRules = { required: true, maxLength: 50 }; + const customerIdRules = { required: true, number: true }; + const orderIdRules = { number: true }; + const invoiceNumberRules = { maxLength: 50 }; + const descriptionRules = { maxLength: 500 }; + const amountRules = { required: true, number: true }; + const currencyCodeRules = { maxLength: 10 }; + const transactionTypeRules = { maxLength: 50 }; + const paymentGatewayRules = { maxLength: 100 }; + const statusRules = { maxLength: 50 }; + + const dataManager = new DataManager({ + url: 'http://localhost:5283/api/grid/url', + insertUrl: 'http://localhost:5283/api/grid/insert', + updateUrl: 'http://localhost:5283/api/grid/update', + removeUrl: 'http://localhost:5283/api/grid/remove', + batchUrl: 'http://localhost:5283/api/grid/batch', + adaptor: new CustomAdaptor(), + }); + + const filterSettings: FilterSettingsModel = { type: 'Excel' } + const editSettings: EditSettingsModel = { allowAdding: true, allowEditing: true, allowDeleting: true, mode: "Batch" }; + const toolbar: ToolbarItems[] = ['Add', 'Edit', 'Delete', 'Update', 'Cancel', 'Search']; + + return ( +
+ + + + + + + + + + + + + + + + + + +
+ ); +}; + +export default App; \ No newline at end of file diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/CustomAdaptor.ts b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/CustomAdaptor.ts new file mode 100644 index 0000000..f5f4047 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/CustomAdaptor.ts @@ -0,0 +1,69 @@ +// File: src/app/custom-adaptor.ts +import { type BatchChanges } from "@syncfusion/ej2-react-grids"; +import { + DataManager, + UrlAdaptor, + type ReturnOption, + type DataResult, +} from "@syncfusion/ej2-data"; + +export class CustomAdaptor extends UrlAdaptor { + public override processResponse(data: DataResult): ReturnOption { + const original = data as any; + if (original && original.result) { + let i = 0; + original.result.forEach((item: any) => (item.SNo = ++i)); + } + return original; + } + + public override beforeSend( + dm: DataManager, + request: Request, + settings?: any, + ): void { + super.beforeSend(dm, request, settings); + } + + public override insert(dm: DataManager, data: DataResult) { + return { + url: `${dm.dataSource["insertUrl"]}`, + type: "POST", + contentType: "application/json; charset=utf-8", + data: JSON.stringify({ value: data }), + }; + } + + public override update(dm: DataManager, _keyField: string, value: any) { + return { + url: `${dm.dataSource["updateUrl"]}`, + type: "POST", + contentType: "application/json; charset=utf-8", + data: JSON.stringify({ value }), + }; + } + + public override remove(dm: DataManager, keyField: string, value: any) { + const keyValue = + value && typeof value === "object" ? value[keyField] : value; + return { + url: `${dm.dataSource["removeUrl"]}`, + type: "POST", + contentType: "application/json; charset=utf-8", + data: JSON.stringify({ key: keyValue }), + }; + } + + public override batchRequest(dm: DataManager, changes: BatchChanges) { + return { + url: `${dm.dataSource["batchUrl"]}`, + type: "POST", + contentType: "application/json; charset=utf-8", + data: JSON.stringify({ + added: changes.addedRecords, + changed: changes.changedRecords, + deleted: changes.deletedRecords, + }), + }; + } +} diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/assets/react.svg b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/index.css b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/index.css new file mode 100644 index 0000000..53a481e --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/index.css @@ -0,0 +1,10 @@ +@import '../node_modules/@syncfusion/ej2-base/styles/bootstrap5.3.css'; +@import '../node_modules/@syncfusion/ej2-buttons/styles/bootstrap5.3.css'; +@import '../node_modules/@syncfusion/ej2-calendars/styles/bootstrap5.3.css'; +@import '../node_modules/@syncfusion/ej2-dropdowns/styles/bootstrap5.3.css'; +@import '../node_modules/@syncfusion/ej2-inputs/styles/bootstrap5.3.css'; +@import '../node_modules/@syncfusion/ej2-navigations/styles/bootstrap5.3.css'; +@import '../node_modules/@syncfusion/ej2-popups/styles/bootstrap5.3.css'; +@import '../node_modules/@syncfusion/ej2-splitbuttons/styles/bootstrap5.3.css'; +@import '../node_modules/@syncfusion/ej2-notifications/styles/bootstrap5.3.css'; +@import '../node_modules/@syncfusion/ej2-react-grids/styles/bootstrap5.3.css'; \ No newline at end of file diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/main.tsx b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/main.tsx new file mode 100644 index 0000000..bef5202 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.app.json b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.app.json new file mode 100644 index 0000000..a9b5a59 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.json b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.node.json b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.node.json new file mode 100644 index 0000000..8a67f62 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/vite.config.ts b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/vite.config.ts new file mode 100644 index 0000000..e6b0f97 --- /dev/null +++ b/connecting-to-database/syncfusion-react-grid-MySQL-Stored-Procedures/grid_mysql.client/vite.config.ts @@ -0,0 +1,61 @@ +import { fileURLToPath, URL } from 'node:url'; + +import { defineConfig } from 'vite'; +import plugin from '@vitejs/plugin-react'; +import fs from 'fs'; +import path from 'path'; +import child_process from 'child_process'; +import { env } from 'process'; + +const baseFolder = + env.APPDATA !== undefined && env.APPDATA !== '' + ? `${env.APPDATA}/ASP.NET/https` + : `${env.HOME}/.aspnet/https`; + +const certificateName = "ticketmanagement.client"; +const certFilePath = path.join(baseFolder, `${certificateName}.pem`); +const keyFilePath = path.join(baseFolder, `${certificateName}.key`); + +if (!fs.existsSync(baseFolder)) { + fs.mkdirSync(baseFolder, { recursive: true }); +} + +if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) { + if (0 !== child_process.spawnSync('dotnet', [ + 'dev-certs', + 'https', + '--export-path', + certFilePath, + '--format', + 'Pem', + '--no-password', + ], { stdio: 'inherit', }).status) { + throw new Error("Could not create certificate."); + } +} + +const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` : + env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'https://localhost:7290'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [plugin()], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + }, + server: { + proxy: { + '^/weatherforecast': { + target, + secure: false + } + }, + port: parseInt(env.DEV_SERVER_PORT || '59074'), + https: { + key: fs.readFileSync(keyFilePath), + cert: fs.readFileSync(certFilePath), + } + } +})