refactor(sql): promote the single-row limit onto ISqlDialect
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
@@ -41,8 +41,7 @@ public static class SqlGroupPlanner
|
||||
/// up front, so reaching one here means a caller built a definition by hand with a broken invariant.
|
||||
/// </exception>
|
||||
/// <exception cref="NotSupportedException">
|
||||
/// A tag carries <see cref="SqlTagModel.Query"/> (design §5.4, deferred to P3), or a
|
||||
/// <c>topByTimestamp</c> selector is planned for a provider whose row-limit syntax is not yet modelled.
|
||||
/// A tag carries <see cref="SqlTagModel.Query"/> (design §5.4, deferred to P3).
|
||||
/// <b>Deliberately loud rather than skipped:</b> silently dropping a tag would leave an authored node
|
||||
/// permanently unfed with nothing in the log, and the parser makes this branch unreachable in practice.
|
||||
/// </exception>
|
||||
@@ -157,7 +156,10 @@ public static class SqlGroupPlanner
|
||||
|
||||
/// <summary>
|
||||
/// Emits <c>SELECT <cols> FROM <table> WHERE <whereColumn> = @w</c>, or — for a
|
||||
/// <c>topByTimestamp</c> selector — <c>SELECT TOP 1 <cols> FROM <table> ORDER BY <ts> DESC</c>.
|
||||
/// <c>topByTimestamp</c> selector — the single-row form
|
||||
/// <c>SELECT <limit> <cols> FROM <table> ORDER BY <ts> DESC <limit></c>, whose
|
||||
/// row limit comes from <see cref="ISqlDialect.SingleRowLimitPrefix"/> /
|
||||
/// <see cref="ISqlDialect.SingleRowLimitSuffix"/> (T-SQL fills the prefix: <c>SELECT TOP 1 …</c>).
|
||||
/// <para>The SELECT list is each member's <c>columnName</c> (distinct, in first-appearance order),
|
||||
/// followed by each distinct member <c>timestampColumn</c> — so members of one row may carry different
|
||||
/// timestamp columns without splitting the group. The where-column itself is <b>not</b> selected: every
|
||||
@@ -191,18 +193,13 @@ public static class SqlGroupPlanner
|
||||
|
||||
if (!Blank(first.RowSelectorTopByTimestamp))
|
||||
{
|
||||
// "TOP 1" is T-SQL. Other providers spell the row limit differently (LIMIT 1, FETCH FIRST,
|
||||
// ROWNUM), and ISqlDialect does not model it yet because v1 constructs SqlServer only — so refuse
|
||||
// loudly rather than emit a statement that would not parse. Promote a row-limit member onto
|
||||
// ISqlDialect when P2 adds Postgres/ODBC.
|
||||
if (dialect.Provider != SqlProvider.SqlServer)
|
||||
throw new NotSupportedException(
|
||||
$"The wide-row 'topByTimestamp' row selector needs a provider-specific row limit; " +
|
||||
$"{dialect.Provider} is not modelled yet (v1 constructs SqlServer only).");
|
||||
|
||||
// The row limit is dialect syntax and sits at opposite ends of the statement per provider
|
||||
// (T-SQL "SELECT TOP 1 …", SQLite/Postgres/MySQL "… LIMIT 1"), so both ends are emitted
|
||||
// unconditionally and the dialect decides which one it fills. See ISqlDialect.SingleRowLimitPrefix.
|
||||
var sql = string.Concat(
|
||||
"SELECT TOP 1 ", columns, " FROM ", table,
|
||||
" ORDER BY ", dialect.QuoteIdentifier(first.RowSelectorTopByTimestamp!), " DESC");
|
||||
"SELECT ", dialect.SingleRowLimitPrefix, columns, " FROM ", table,
|
||||
" ORDER BY ", dialect.QuoteIdentifier(first.RowSelectorTopByTimestamp!), " DESC",
|
||||
dialect.SingleRowLimitSuffix);
|
||||
return new SqlQueryPlan(SqlTagModel.WideRow, groupKey, sql, [], [], members, selected);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user