I'm going to try to come at this from a different direction.
When you start putting long chunks of data in files, you quickly start running into the need for templating. For instance, your SQL query string needs to support both forwards and backwards sorting. Or the HTML you're generating needs a person's name substituted in. However, we don't want to create a whole templating language from scratch—that's a huge undertaking.
Embedding file names in your code is also a bit fraught. We don't really include any compile-time file names in Swift code currently; it's too big a pain, and the difference between compile-time and runtime locations can be too confusing.
So maybe we should take a different approach here: Instead of having a file name literal syntax, we should make it easier to write functions which merely generate big wads of string data. This would allow much more sophisticated behavior and easier handling for the compiler, at the cost of having a little bit of Swift syntax in the files and giving them a .swift
extension.
So with this design, the execLongQuery()
function would look more like:
func execLongQuery() {
let sql = makeLongQuery()
database.execute(sql)
}
And the actual query definition might look like:
func makeLongQuery() -> String """
SELECT events.id, events.created_at, ...
FROM events, ...
WHERE ...
"""
If you wanted to support changing the sort order, that might look like:
func makeLongQuery(ascending: Bool = true) -> String """
SELECT events.id, events.created_at, ...
FROM events, ...
WHERE ...
ORDER BY events.created_at \(ascending ? "ASC" : "DESC")
"""
If you ever want to use more complicated logic than can easily fit into an interpolation…well, refactor it into a function with a normal body. It's called in exactly the same way.
A function like this could be declared to return any ExpressibleByStringLiteral
type. For example, if you had a "safe SQL statement" type or a "safe HTML fragment" type with automatic escaping, you could declare your function to use those instead.
And as for supporting Data
values? Conform Data
to ExpressibleByStringLiteral
and you can declare your function to return Data
instead of String
.