-
-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Aliases in select queries can cause fatal errors #582
Comments
Fluent performs column aliasing unconditionally as a defense against name collisions in joins - ironically, I was just telling @0xTim the other day about how to get around exactly this issue; in his case, the problem was the combination of long table names and long column names, and using I'm not sure of a solution that would solve this "automatically" without requiring support from individual drivers at the very least - this is how we apply SHA-1 hashing for constraint names in MySQL. I hesitate to apply a similar solution elsewhere, however; the hashing just ends up yielding confusing names and requiring even uglier workarounds in the database schema API. |
It looks like
The code compiles with that class, but not when I add:
Build errors:
|
Another thing to consider is adding helpful details to this message:
One idea would be to compute the alias string length and add something like this to the fatal error message: "Check if your database's name length limit is smaller than n characters, which is the number of characters used by this field's alias." |
@rausnitz Ooof, you're right, In the meantime, what you can do in such a case is drop down to SQLKit - for the equivalent of the simple // With aliasing:
let demoUsers = try await (app.db as! any SQLDatabase).select()
.columns(SQLColumn(SQLLiteral.all, table: SQLIdentifier("alias_examples")))
.from(SQLAlias(SQLQualifiedTable(DemoUser.schema, space: DemoUser.space), as: SQLIdentifier("alias_examples"))
.all(decoding: DemoUser.self)
// Without aliasing:
let demoUsers = try await (app.db as! any SQLDatabase).select()
.columns(SQLLiteral.all)
.from(SQLQualifiedTable(DemoUser.schema, space: DemoUser.space))
.all(decoding: DemoUser.self) (Of course, in SQLKit you don't need the aliasing for a query like this, and the |
The problem is that that message can come up for several other issues that have nothing to do with aliasing. It's extremely unfortunate that Tanner built this to FWIW, hitting a length limit on non-key identifiers as you have is not a particularly common problem in our experience - it's only come up two or three times ever, and we don't have a good solution. It's one of the many, many, many, many, many, and did I mention MANY!!! 😅 design flaws in Fluent that we plan to resolve with Fluent 5. |
If you know what you have in mind, I'd be willing to work on the implementation. |
@rausnitz There are two possible approaches I was thinking of, which aren't mutually exclusive, although one is certainly easier than the other:
|
At this point, I have to consider fixing this out of scope for Fluent 4. I'll leave this open as a reminder for Fluent 5 to provide a clean solution via driver support and intelligent aliasing. |
Describe the bug
Using aliases in
select
queries will cause a fatal error if the following two things happen:Postgres has a character limit of 63 for column names.
FluentKit always uses aliases for column names in
select
queries:fluent-kit/Sources/FluentSQL/SQLQueryConverter.swift
Line 56 in ccea982
It combines the Postgres schema name, table name, and column name to form the alias:
fluent-kit/Sources/FluentSQL/SQLQueryConverter.swift
Line 208 in ccea982
Postgres will return data to the client without erroring, but it will truncate the alias name, so FluentKit will treat the data like it's missing.
If the column is an
@OptionalField
, the value will benil
even if there was data in the database.If the column is a
@Field
, the value will benil
, and referencing the property in Swift will cause a fatal error.To Reproduce
I created this Model:
(It's an extreme example, but we did encounter this fatal error in a real backend app, due to a column with a long name in a table with a long name.)
Then I added a query to the
configure(_:)
function in a Vapor app:Here's what I see in the logs:
The data returned by Postgres truncates the alias to its first 63 characters,
users_sixty_character_column_1234567890_1234567890_1234567890_1
.Expected behavior
I think names that are allowed in Postgres should be usable in FluentKit.
Maybe it could automatically skip aliasing when the alias exceeds 63 characters. (Though, this would be problematic because other databases probably don't use this same limit, and even Postgres databases can be configured with different limits.)
Maybe there could be a property like
static let shouldAliasColumns: Bool
onModel
that lets you control whether its columns are aliased.Environment
This is not environment-dependent.
The text was updated successfully, but these errors were encountered: