Skip to content

Commit

Permalink
Enhancement: Carbunql.Fluent namespace
Browse files Browse the repository at this point in the history
Added the ability to convert a select query to a CTE.
Added the ability to convert a select query to a subquery.
Added the ability to convert a select query to a count query.
Added the ability to convert a select query to an append query.
Added the ability to convert a select query to an update query.
Added the ability to convert a select query to a delete query.
Added the ability to convert a select query to a merge query.
Added the ability to convert a select query to a create table query.
  • Loading branch information
mk3008 committed Sep 1, 2024
1 parent db5b6ce commit b748ec7
Show file tree
Hide file tree
Showing 10 changed files with 872 additions and 151 deletions.
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ public static string GenerateReportQuery(bool includeSummary, DateTime summaryMo
sale_date
""";

var dailySummary = FluentTable.Create(dailySummaryQuery, "daily_summary", "d");

string monthlySummaryQuery = """
SELECT
date_trunc('month', sale_date) + '1 month -1 day' as sale_date
Expand All @@ -122,21 +124,21 @@ public static string GenerateReportQuery(bool includeSummary, DateTime summaryMo
date_trunc('month', sale_date) + '1 month -1 day'
""";

var monthlySummary = FluentTable.Create(monthlySummaryQuery, "monthly_summary", "m");

// Create daily summary query
var sq = new SelectQuery()
.With(dailySummaryQuery, "daily_summary")
.From("daily_summary", "d")
.SelectAll("d");
.From(dailySummary)
.SelectAll(dailySummary);

if (includeSummary)
{
// Add monthly summary query with UNION ALL
sq.UnionAll(() =>
{
var xsq = new SelectQuery()
.With(monthlySummaryQuery, "monthly_summary")
.From("monthly_summary", "m")
.SelectAll("m");
.From(monthlySummary)
.SelectAll(monthlySummary);
return xsq;
});
}
Expand Down
14 changes: 8 additions & 6 deletions demo/DynamicCTE/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ GROUP BY
sale_date
""";

var dailySummary = FluentTable.Create(dailySummaryQuery, "daily_summary", "d");

string monthlySummaryQuery = """
SELECT
date_trunc('month', sale_date) + '1 month -1 day' as sale_date
Expand All @@ -42,21 +44,21 @@ GROUP BY
date_trunc('month', sale_date) + '1 month -1 day'
""";

var monthlySummary = FluentTable.Create(monthlySummaryQuery, "monthly_summary", "m");

// Create daily summary query
var sq = new SelectQuery()
.With(dailySummaryQuery, "daily_summary")
.From("daily_summary", "d")
.SelectAll("d");
.From(dailySummary)
.SelectAll(dailySummary);

if (includeSummary)
{
// Add monthly summary query with UNION ALL
sq.UnionAll(() =>
{
var xsq = new SelectQuery()
.With(monthlySummaryQuery, "monthly_summary")
.From("monthly_summary", "m")
.SelectAll("m");
.From(monthlySummary)
.SelectAll(monthlySummary);
return xsq;
});
}
Expand Down
118 changes: 59 additions & 59 deletions demo/Parse/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,80 +7,80 @@
var sql = ReadMultiLine();
if (string.IsNullOrEmpty(sql))
{
sql = @"
with
dat(line_id, name, unit_price, quantity, tax_rate) as (
values
(1, 'apple' , 105, 5, 0.07),
(2, 'orange', 203, 3, 0.07),
(3, 'banana', 233, 9, 0.07),
(4, 'tea' , 309, 7, 0.08),
(5, 'coffee', 555, 9, 0.08),
(6, 'cola' , 456, 2, 0.08)
),
detail as (
select
q.*,
trunc(q.price * (1 + q.tax_rate)) - q.price as tax,
q.price * (1 + q.tax_rate) - q.price as raw_tax
from
(
sql = """
with
dat(line_id, name, unit_price, quantity, tax_rate) as (
values
(1, 'apple' , 105, 5, 0.07),
(2, 'orange', 203, 3, 0.07),
(3, 'banana', 233, 9, 0.07),
(4, 'tea' , 309, 7, 0.08),
(5, 'coffee', 555, 9, 0.08),
(6, 'cola' , 456, 2, 0.08)
),
detail as (
select
q.*,
trunc(q.price * (1 + q.tax_rate)) - q.price as tax,
q.price * (1 + q.tax_rate) - q.price as raw_tax
from
(
select
dat.*,
(dat.unit_price * dat.quantity) as price
from
dat
) q
),
tax_summary as (
select
dat.*,
(dat.unit_price * dat.quantity) as price
d.tax_rate,
trunc(sum(raw_tax)) as total_tax
from
dat
) q
),
tax_summary as (
select
d.tax_rate,
trunc(sum(raw_tax)) as total_tax
from
detail d
group by
d.tax_rate
)
select
line_id,
name,
unit_price,
quantity,
tax_rate,
price,
price + tax as tax_included_price,
tax
from
(
select
line_id,
detail d
group by
d.tax_rate
)
select
line_id,
name,
unit_price,
quantity,
tax_rate,
price,
tax + adjust_tax as tax
price + tax as tax_included_price,
tax
from
(
select
q.*,
case when q.total_tax - q.cumulative >= q.priority then 1 else 0 end as adjust_tax
line_id,
name,
unit_price,
quantity,
tax_rate,
price,
tax + adjust_tax as tax
from
(
select
d.*,
s.total_tax,
sum(d.tax) over (partition by d.tax_rate) as cumulative,
row_number() over (partition by d.tax_rate order by d.raw_tax % 1 desc, d.line_id) as priority
select
q.*,
case when q.total_tax - q.cumulative >= q.priority then 1 else 0 end as adjust_tax
from
detail d
inner join tax_summary s on d.tax_rate = s.tax_rate
(
select
d.*,
s.total_tax,
sum(d.tax) over (partition by d.tax_rate) as cumulative,
row_number() over (partition by d.tax_rate order by d.raw_tax % 1 desc, d.line_id) as priority
from
detail d
inner join tax_summary s on d.tax_rate = s.tax_rate
) q
) q
) q
) q
order by
line_id
";
order by
line_id
""";
}

var sq = SelectQuery.Parse(sql);
Expand Down
117 changes: 41 additions & 76 deletions demo/QuerySource/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Carbunql;
using Carbunql.Building;
using Carbunql.Fluent;

var sql = """
select
Expand All @@ -16,82 +17,46 @@ sales as s

var query = SelectQuery.Parse(sql)
.OverrideSelect("journal_date", (source, item) => $"greatest({item}, {source.Query.AddParameter(":lower_limit", lower_limit)})")
.AddNotExists(["sale_id"], "sale_journals")
.AddWhere("request_timestamp", (source) => $"{source.Alias}.request_timestamp >= :lower_limit")
.ToCTEQuery("final", "f")
.NotExists(["sale_id"], "sale_journals")
.GreaterThanOrEqual("request_timestamp", ":lower_limit")
.ToCteQuery("final", "f", out var final)
.SelectAll(final)
.ToInsertQuery("sale_journals");

Console.WriteLine(query.ToText());

var fixedsql = """
select
s.sale_id
, s.store_id
, s.sale_date as journal_date
, s.price + s.tax as journal_price
, s.request_timestamp
from
sales as s
""";

var modDate = new DateTime(2024, 7, 1);
var modQuery = new SelectQuery()
// Define expected values (current values) as a CTE named 'expect'
.AddCTEQuery("""
select distinct on(sale_id)
sale_id
, store_id
, journal_date
, journal_price
from
sale_journals
where
journal_price > 0
order by
sale_id
, sale_journal_id desc
""", "expect")
// Define the correct values as a CTE named 'actual'
.AddCTEQuery(fixedsql, "actual")
// Compare the expected and correct values, and format the differences with red/black formatting
.AddFrom("expect", "exp")
.AddJoin("inner join", "actual", "act", "exp.sale_id = act.sale_id")
.AddWhere("exp.journal_price <> act.journal_price")
.OverrideSelect("journal_date", (source, item) => $"greatest({item}, {source.Query.AddParameter(":mod_date", modDate)})")
.AddSelectAll("exp")
.RemoveSelect("journal_price")
.AddSelect("exp.journal_price * -1", "reverse_price")
.AddSelect("act.journal_price * +1", "collect_price")
// Define the query result with red/black formatting as a CTE named 'diff' and select it
.ToCTEQuery("diff", "r")
// Since we want to process red entries, the collect_price value is unnecessary; use reverse_price as the journal value
.RemoveSelect("collect_price")
.RenameSelect("reverse_price", "journal_price")
// To process black entries, generate a UNION ALL query
.AddSelectQuery("union all", owner =>
{
return new SelectQuery()
// Since we want to use the CTE 'diff', import the CTE information
.ImportCTEQueries(owner)
// Define the black entry selection query, similar to the red entry
.AddFrom("diff", "c")
.AddSelectAll("c")
.RemoveSelect("reverse_price")
.RenameSelect("collect_price", "journal_price");
})
// Convert to an insert query
.ToInsertQuery("sale_journals");




Console.WriteLine(modQuery.ToText());


Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine(";");

/*
INSERT INTO
sale_journals(sale_id, store_id, journal_date, journal_price, request_timestamp)
WITH
final AS (
SELECT
s.sale_id,
s.store_id,
GREATEST(s.sale_date, Carbunql.SelectQuery) AS journal_date,
s.price AS journal_price,
s.request_timestamp
FROM
sales AS s
WHERE
NOT EXISTS (
SELECT
*
FROM
sale_journals AS x
WHERE
x.sale_id = s.sale_id
)
AND :lower_limit <= s.request_timestamp
)
SELECT
f.sale_id,
f.store_id,
f.journal_date,
f.journal_price,
f.request_timestamp
FROM
final AS f
;
*/
18 changes: 18 additions & 0 deletions src/Carbunql/Building/ReadQueryExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public static class ReadQueryExtension
/// <param name="source">The source IReadQuery.</param>
/// <param name="alias">The alias for the CTE.</param>
/// <returns>A tuple containing the SelectQuery and the CommonTable representing the CTE.</returns>
[Obsolete("use ToCte")]
public static (SelectQuery, CommonTable) ToCTE(this IReadQuery source, string alias)
{
var sq = new SelectQuery();
Expand All @@ -27,6 +28,23 @@ public static (SelectQuery, CommonTable) ToCTE(this IReadQuery source, string al
return (sq, ct);
}

/// <summary>
/// Converts the IReadQuery to a CommonTableExpression (CTE) with the specified alias.
/// </summary>
/// <param name="source">The source IReadQuery.</param>
/// <param name="alias">The alias for the CTE.</param>
/// <returns>A tuple containing the SelectQuery and the CommonTable representing the CTE.</returns>
public static (SelectQuery, CommonTable) ToCte(this IReadQuery source, string alias)
{
var sq = new SelectQuery();

sq.WithClause ??= new WithClause();
var ct = source.ToCommonTable(alias);
sq.WithClause.Add(ct);

return (sq, ct);
}

/// <summary>
/// Converts the IReadQuery to a CommonTable with the specified alias.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Carbunql.Fluent;
/// <summary>
/// Provides extension methods for adding and clearing comment clauses for objects implementing the <see cref="ICommentable"/> interface.
/// </summary>
public static class ICommentableExtension
public static class ICommentableExtensions
{
/// <summary>
/// Adds a comment to the object.
Expand Down
Loading

0 comments on commit b748ec7

Please sign in to comment.