Skip to content

Conversation

ptoffy
Copy link
Member

@ptoffy ptoffy commented Apr 15, 2025

This adds support for the LAG window function which allows support for accessing a value from a previous row

@ptoffy ptoffy requested a review from gwynne as a code owner April 15, 2025 14:11
@ptoffy ptoffy changed the title Lag expression Add SQLLAGExpression Apr 15, 2025
Copy link

codecov bot commented Apr 15, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 91.86%. Comparing base (785f0bb) to head (052e899).

Additional details and impacted files
@@            Coverage Diff             @@
##             main       #3      +/-   ##
==========================================
+ Coverage   91.68%   91.86%   +0.18%     
==========================================
  Files          61       63       +2     
  Lines         926      947      +21     
==========================================
+ Hits          849      870      +21     
  Misses         77       77              
Files with missing lines Coverage Δ
...LKitExtras/Expressions/SQLLAG+FluentKeypaths.swift 100.00% <100.00%> (ø)
...as/SQLKitExtras/Expressions/SQLLAGExpression.swift 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member

@gwynne gwynne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on the serialize method is purely advisory; I would really prefer to add syntax that provides more general support for window functions rather than for just one specific function. Indeed, even this one function's implementation is incomplete without at least adding support support for PARTITION BY and FILTER and correct support for ORDER BY. The correct syntax of lag() is lag(value[, offset[, default]]), per https://www.postgresql.org/docs/17/functions-window.html, https://dev.mysql.com/doc/refman/9.0/en/window-function-descriptions.html#function_lag, and https://sqlite.org/windowfunctions.html#built_in_window_functions - where you got this OVER (ORDER BY 1) DEFAULT 0 syntax I can't even guess.

Comment on lines +31 to +39
serializer.write("LAG(")
value.serialize(to: &serializer)
serializer.write(") OVER (ORDER BY ")
offset.serialize(to: &serializer)
serializer.write(")")
if let defaultValue = defaultValue {
serializer.write(" DEFAULT ")
defaultValue.serialize(to: &serializer)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's always preferable to leverage existing expressions when possible in generating output for new ones - and to use serializer.statement {} when the syntax allows. For example:

Suggested change
serializer.write("LAG(")
value.serialize(to: &serializer)
serializer.write(") OVER (ORDER BY ")
offset.serialize(to: &serializer)
serializer.write(")")
if let defaultValue = defaultValue {
serializer.write(" DEFAULT ")
defaultValue.serialize(to: &serializer)
}
serializer.statement {
$0.append(SQLFunction("lag", args: value))
$0.append("OVER")
$0.append(SQLGroupExpression(SQLList([SQLRaw("ORDER BY"), offset], separator: SQLRaw(" ")))
if let defaultValue = self.defaultValue {
$0.append(SQLLiteral.default, defaultValue)
}
}

(keeping in mind that this is not even correct syntax for LAG to begin with - see the overall review comment for more details)

@ptoffy
Copy link
Member Author

ptoffy commented Apr 17, 2025

@gwynne do you want to add proper window function support? I think that should be doable. As for the LAG syntax, what I added is what I've successfully been using in a production system for some time now - I got it from an example somewhere (I think it was https://www.geeksforgeeks.org/postgresql-lag-function/ but I'm not 100% sure)

@gwynne
Copy link
Member

gwynne commented Apr 17, 2025

I definitely want to add proper support, if we're gonna add anything at all.

Also, that link also shows correct syntax. I think what you have mostly works by accident 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants