Skip to content

Commit d0f7dc0

Browse files
author
fabien.menager
committed
Apply code review suggestions and switch back to SQL server SQL, without query execution, only SQL display
1 parent bd5df17 commit d0f7dc0

7 files changed

Lines changed: 18 additions & 127 deletions

File tree

.editorconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#use soft tabs (spaces) for indentation
1010
indent_style = space
11+
indent_size = 4
1112

1213
#Formatting - new line options
1314

@@ -131,3 +132,7 @@ dotnet_naming_symbols.instance_fields.applicable_kinds = field
131132

132133
dotnet_naming_style.instance_field_style.capitalization = camel_case
133134
dotnet_naming_style.instance_field_style.required_prefix = _
135+
136+
[*.{csproj,props,targets}]
137+
indent_style = space
138+
indent_size = 2

samples/ReadmeSample/ApplicationDbContext.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using EntityFrameworkCore.Projectables.Extensions;
2-
using EntityFrameworkCore.Projectables.Infrastructure;
3-
using Microsoft.EntityFrameworkCore;
1+
using Microsoft.EntityFrameworkCore;
42
using ReadmeSample.Entities;
53

64
namespace ReadmeSample;
@@ -14,7 +12,7 @@ public class ApplicationDbContext : DbContext
1412

1513
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
1614
{
17-
optionsBuilder.UseSqlite("Data Source=ReadmeSample.db");
15+
optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=ReadmeSample;Trusted_Connection=True");
1816

1917
// Feature 10: Compatibility mode
2018
// Full (default) — expands every query on each invocation; maximum compatibility.

samples/ReadmeSample/ConsoleHelper.cs

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
namespace ReadmeSample;
55

66
/// <summary>Spectre.Console rendering helpers used by Program.cs.</summary>
7-
internal static class ConsoleHelper
7+
static internal partial class ConsoleHelper
88
{
99
/// <summary>
1010
/// Applies Spectre.Console markup to a raw SQL string:
1111
/// string literals → green, SQL keywords → bold cyan, ef_* helpers → dim grey.
1212
/// </summary>
13-
public static string SqlMarkup(string sql)
13+
private static string SqlMarkup(string sql)
1414
{
1515
// Escape [ and ] so Spectre doesn't misinterpret them as markup tags.
1616
var esc = Markup.Escape(sql);
@@ -20,22 +20,13 @@ public static string SqlMarkup(string sql)
2020
// group 2 → multi-word keywords (INNER JOIN, LEFT JOIN, ORDER BY, GROUP BY)
2121
// group 3 → single-word SQL keywords
2222
// group 4 → SQLite-specific ef_* helper functions
23-
return Regex.Replace(
24-
esc,
25-
@"('[^']*')"
26-
+ @"|(\bINNER JOIN\b|\bLEFT JOIN\b|\bORDER BY\b|\bGROUP BY\b)"
27-
+ @"|(\bSELECT\b|\bFROM\b|\bWHERE\b|\bCASE\b|\bWHEN\b|\bTHEN\b|\bELSE\b|\bEND\b"
28-
+ @"|\bAND\b|\bOR\b|\bNOT\b|\bNULL\b|\bIS\b|\bIN\b|\bON\b|\bAS\b"
29-
+ @"|\bLIMIT\b|\bCOALESCE\b|\bCAST\b)"
30-
+ @"|(\bef_\w+\b)",
31-
m =>
23+
return SqlHighlightRegex().Replace(esc, m =>
3224
{
3325
if (m.Groups[1].Success) return $"[green]{m.Value}[/]";
3426
if (m.Groups[2].Success || m.Groups[3].Success) return $"[bold deepskyblue1]{m.Value}[/]";
3527
if (m.Groups[4].Success) return $"[grey50]{m.Value}[/]";
3628
return m.Value;
37-
},
38-
RegexOptions.IgnoreCase);
29+
});
3930
}
4031

4132
/// <summary>Renders a numbered feature section header using a yellow rule.</summary>
@@ -61,29 +52,8 @@ public static void ShowSql(string sql)
6152
});
6253
AnsiConsole.WriteLine();
6354
}
64-
65-
/// <summary>Formats a currency amount in bold spring-green.</summary>
66-
public static string Money(decimal v) =>
67-
$"[bold springgreen2]{Markup.Escape(v.ToString("C"))}[/]";
68-
69-
/// <summary>Formats a boolean as coloured true/false.</summary>
70-
public static string BoolMark(bool v) =>
71-
v ? "[bold chartreuse1]true[/]" : "[bold red1]false[/]";
72-
73-
/// <summary>Formats a priority label with traffic-light colouring.</summary>
74-
public static string PriorityMark(string? p) => p switch
75-
{
76-
"High" => "[bold red1]High[/]",
77-
"Medium" => "[bold yellow]Medium[/]",
78-
_ => "[bold green]Low[/]",
79-
};
80-
81-
/// <summary>Formats an order status string with semantic colouring.</summary>
82-
public static string StatusMark(string? s) => s switch
83-
{
84-
"Fulfilled" => $"[bold green]{Markup.Escape(s)}[/]",
85-
"Cancelled" => $"[bold red1]{Markup.Escape(s)}[/]",
86-
_ => $"[bold yellow]{Markup.Escape(s ?? "?")}[/]",
87-
};
55+
56+
[GeneratedRegex(@"('[^']*')|(\bINNER JOIN\b|\bLEFT JOIN\b|\bORDER BY\b|\bGROUP BY\b)|(\bSELECT\b|\bFROM\b|\bWHERE\b|\bCASE\b|\bWHEN\b|\bTHEN\b|\bELSE\b|\bEND\b|\bAND\b|\bOR\b|\bNOT\b|\bNULL\b|\bIS\b|\bIN\b|\bON\b|\bAS\b|\bLIMIT\b|\bCOALESCE\b|\bCAST\b)|(\bef_\w+\b)", RegexOptions.IgnoreCase, matchTimeoutMilliseconds: 500)]
57+
private static partial Regex SqlHighlightRegex();
8858
}
8959

samples/ReadmeSample/Entities/Order.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
5-
using System.Threading.Tasks;
6-
using EntityFrameworkCore.Projectables;
1+
using EntityFrameworkCore.Projectables;
72

83
namespace ReadmeSample.Entities;
94

samples/ReadmeSample/Extensions/UserExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace ReadmeSample.Extensions;
66
public static class UserExtensions
77
{
88
/// <summary>
9-
/// Returns the most recent fulfilled order for the user.
9+
/// Returns the most recent order for the user.
1010
/// Matches the README example — inlined into SQL via [Projectable].
1111
/// </summary>
1212
[Projectable]

samples/ReadmeSample/Program.cs

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using Microsoft.EntityFrameworkCore;
22
using ReadmeSample;
33
using ReadmeSample.Dtos;
4-
using ReadmeSample.Entities;
54
using ReadmeSample.Extensions;
65
using Spectre.Console;
76
using static ReadmeSample.ConsoleHelper;
@@ -22,32 +21,6 @@
2221
// Bootstrap
2322
// ─────────────────────────────────────────────────────────────────────────────
2423
await using var dbContext = new ApplicationDbContext();
25-
dbContext.Database.EnsureDeleted();
26-
dbContext.Database.EnsureCreated();
27-
28-
// ─────────────────────────────────────────────────────────────────────────────
29-
// Seed data
30-
// ─────────────────────────────────────────────────────────────────────────────
31-
var user = new User { UserName = "Jon", EmailAddress = "jon@doe.com" };
32-
var supplier = new Supplier { Name = "Acme Stationery" };
33-
var pen = new Product { Name = "Blue Pen", ListPrice = 1.50m, Supplier = supplier };
34-
var book = new Product { Name = "C# in Depth", ListPrice = 35.99m }; // no supplier → null-conditional demo
35-
36-
var fulfilledOrder = new Order
37-
{
38-
User = user, TaxRate = .19m, Status = OrderStatus.Fulfilled,
39-
CreatedDate = DateTime.UtcNow.AddDays(-2), FulfilledDate = DateTime.UtcNow.AddDays(-1),
40-
Items = [new OrderItem { Product = pen, Quantity = 5 }, new OrderItem { Product = book, Quantity = 1 }],
41-
};
42-
var pendingOrder = new Order
43-
{
44-
User = user, TaxRate = .19m, Status = OrderStatus.Pending,
45-
CreatedDate = DateTime.UtcNow, FulfilledDate = null,
46-
Items = [new OrderItem { Product = pen, Quantity = 2 }],
47-
};
48-
49-
dbContext.AddRange(user, supplier, pen, book, fulfilledOrder, pendingOrder);
50-
dbContext.SaveChanges();
5124

5225
// ─────────────────────────────────────────────────────────────────────────────
5326
// Feature 1 — Properties & methods
@@ -61,15 +34,6 @@
6134
});
6235

6336
ShowSql(totalsQuery.ToQueryString());
64-
foreach (var row in totalsQuery)
65-
{
66-
AnsiConsole.MarkupLine(
67-
$" [dim]Order #{row.Id}[/]"
68-
+ $" subtotal={Money(row.Subtotal)}"
69-
+ $" tax={Money(row.Tax)}"
70-
+ $" grand total={Money(row.GrandTotal)}"
71-
+ $" [dim]−10%[/]={Money(row.Discounted10Pct)}");
72-
}
7337

7438
// ─────────────────────────────────────────────────────────────────────────────
7539
// Feature 2 — Extension methods
@@ -81,9 +45,6 @@
8145
.Select(u => new { u.UserName, LatestOrderGrandTotal = u.GetMostRecentOrder()!.GrandTotal });
8246

8347
ShowSql(recentQuery.ToQueryString());
84-
var recent = recentQuery.First();
85-
AnsiConsole.MarkupLine(
86-
$" [white]{Markup.Escape(recent.UserName)}[/]'s most recent order: {Money(recent.LatestOrderGrandTotal)}");
8748

8849
// ─────────────────────────────────────────────────────────────────────────────
8950
// Feature 3 — Constructor projections
@@ -93,14 +54,6 @@
9354
var dtoQuery = dbContext.Orders.Select(o => new OrderSummaryDto(o));
9455

9556
ShowSql(dtoQuery.ToQueryString());
96-
foreach (var dto in dtoQuery)
97-
{
98-
AnsiConsole.MarkupLine(
99-
$" [dim]#{dto.Id}[/] [white]{Markup.Escape(dto.UserName ?? "")}[/]"
100-
+ $" — {Money(dto.GrandTotal)}"
101-
+ $" status={StatusMark(dto.StatusName)}"
102-
+ $" priority={PriorityMark(dto.PriorityLabel)}");
103-
}
10457

10558
// ─────────────────────────────────────────────────────────────────────────────
10659
// Feature 4 — Method overloads
@@ -112,9 +65,6 @@
11265
.Select(u => new { u.UserName, LatestAnyOrderTotal = u.GetMostRecentOrderForUser(true)!.GrandTotal });
11366

11467
ShowSql(withPendingQuery.ToQueryString());
115-
var withPending = withPendingQuery.First();
116-
AnsiConsole.MarkupLine(
117-
$" [white]{Markup.Escape(withPending.UserName)}[/]'s most recent order (incl. pending): {Money(withPending.LatestAnyOrderTotal)}");
11868

11969
// ─────────────────────────────────────────────────────────────────────────────
12070
// Feature 5 — Pattern matching
@@ -124,11 +74,6 @@
12474
var priorityQuery = dbContext.Orders.Select(o => new { o.Id, o.GrandTotal, o.PriorityLabel });
12575

12676
ShowSql(priorityQuery.ToQueryString());
127-
foreach (var row in priorityQuery)
128-
{
129-
AnsiConsole.MarkupLine(
130-
$" [dim]Order #{row.Id}[/] {Money(row.GrandTotal)} → priority={PriorityMark(row.PriorityLabel)}");
131-
}
13277

13378
// ─────────────────────────────────────────────────────────────────────────────
13479
// Feature 6 — Block-bodied members
@@ -138,11 +83,6 @@
13883
var shippingQuery = dbContext.Orders.Select(o => new { o.Id, ShippingCategory = o.GetShippingCategory() });
13984

14085
ShowSql(shippingQuery.ToQueryString());
141-
foreach (var row in shippingQuery)
142-
{
143-
AnsiConsole.MarkupLine(
144-
$" [dim]Order #{row.Id}[/] shipping=[bold]{Markup.Escape(row.ShippingCategory)}[/]");
145-
}
14686

14787
// ─────────────────────────────────────────────────────────────────────────────
14888
// Feature 7 — Null-conditional rewriting
@@ -152,13 +92,6 @@
15292
var supplierQuery = dbContext.Products.Select(p => new { p.Name, p.SupplierName });
15393

15494
ShowSql(supplierQuery.ToQueryString());
155-
foreach (var row in supplierQuery)
156-
{
157-
var sup = row.SupplierName is null
158-
? "[dim](none)[/]"
159-
: $"[bold green]{Markup.Escape(row.SupplierName)}[/]";
160-
AnsiConsole.MarkupLine($" [white]{Markup.Escape(row.Name)}[/] supplier={sup}");
161-
}
16295

16396
// ─────────────────────────────────────────────────────────────────────────────
16497
// Feature 8 — Enum method expansion
@@ -168,11 +101,6 @@
168101
var statusQuery = dbContext.Orders.Select(o => new { o.Id, o.Status, o.StatusDisplayName });
169102

170103
ShowSql(statusQuery.ToQueryString());
171-
foreach (var row in statusQuery)
172-
{
173-
AnsiConsole.MarkupLine(
174-
$" [dim]Order #{row.Id}[/] [dim]{row.Status}[/] → {StatusMark(row.StatusDisplayName)}");
175-
}
176104

177105
// ─────────────────────────────────────────────────────────────────────────────
178106
// Feature 9 — UseMemberBody
@@ -182,11 +110,6 @@
182110
var highValueQuery = dbContext.Orders.Select(o => new { o.Id, o.GrandTotal, o.IsHighValueOrder });
183111

184112
ShowSql(highValueQuery.ToQueryString());
185-
foreach (var row in highValueQuery)
186-
{
187-
AnsiConsole.MarkupLine(
188-
$" [dim]Order #{row.Id}[/] {Money(row.GrandTotal)} → high-value={BoolMark(row.IsHighValueOrder)}");
189-
}
190113

191114
// ─────────────────────────────────────────────────────────────────────────────
192115
// Feature 10 — Compatibility mode

samples/ReadmeSample/ReadmeSample.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net10.0</TargetFramework>
5+
<TargetFrameworks>net10.0;</TargetFrameworks>
66
<IsPackable>false</IsPackable>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
10+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
1111
<PackageReference Include="Spectre.Console" />
1212
</ItemGroup>
1313

0 commit comments

Comments
 (0)