Skip to content

Commit 992bb38

Browse files
committed
Re-use expression aliasing on a query's table
Signed-off-by: Stephen Celis <[email protected]>
1 parent b8c6605 commit 992bb38

File tree

5 files changed

+55
-48
lines changed

5 files changed

+55
-48
lines changed

Documentation/Index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ let managers = users.alias("managers")
617617
618618
let query = users.join(managers, on: managers[id] == users[manager_id])
619619
// SELECT * FROM "users"
620-
// INNER JOIN "users" AS "managers" ON ("managers"."id" = "users"."manager_id")
620+
// INNER JOIN ("users") AS "managers" ON ("managers"."id" = "users"."manager_id")
621621
```
622622
623623
If query results can have ambiguous column names, row values should be accessed with namespaced [column expressions](#expressions). In the above case, `SELECT *` immediately namespaces all columns of the result set.

SQLite Tests/QueryTests.swift

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class QueryTests: XCTestCase {
6060
let query = users.join(managers, on: managers[id] == users[manager_id])
6161

6262
let SQL = "SELECT * FROM \"users\" " +
63-
"INNER JOIN \"users\" AS \"managers\" ON (\"managers\".\"id\" = \"users\".\"manager_id\")"
63+
"INNER JOIN (\"users\") AS \"managers\" ON (\"managers\".\"id\" = \"users\".\"manager_id\")"
6464
ExpectExecutions(db, [SQL: 1]) { _ in for _ in query {} }
6565
}
6666

@@ -70,7 +70,7 @@ class QueryTests: XCTestCase {
7070
let query = users.join(.LeftOuter, managers, on: managers[id] == users[manager_id])
7171

7272
let SQL = "SELECT * FROM \"users\" " +
73-
"LEFT OUTER JOIN \"users\" AS \"managers\" ON (\"managers\".\"id\" = \"users\".\"manager_id\")"
73+
"LEFT OUTER JOIN (\"users\") AS \"managers\" ON (\"managers\".\"id\" = \"users\".\"manager_id\")"
7474
ExpectExecutions(db, [SQL: 1]) { _ in for _ in query {} }
7575
}
7676

@@ -81,7 +81,7 @@ class QueryTests: XCTestCase {
8181
let query = users.join(managers, on: managers[id] == users[manager_id])
8282

8383
let SQL = "SELECT * FROM \"users\" " +
84-
"INNER JOIN \"users\" AS \"managers\" " +
84+
"INNER JOIN (\"users\") AS \"managers\" " +
8585
"ON ((\"managers\".\"id\" = \"users\".\"manager_id\") " +
8686
"AND \"managers\".\"admin\")"
8787
ExpectExecutions(db, [SQL: 1]) { _ in for _ in query {} }
@@ -96,8 +96,8 @@ class QueryTests: XCTestCase {
9696
.join(managed, on: managed[manager_id] == users[id])
9797

9898
let SQL = "SELECT * FROM \"users\" " +
99-
"INNER JOIN \"users\" AS \"managers\" ON (\"managers\".\"id\" = \"users\".\"manager_id\") " +
100-
"INNER JOIN \"users\" AS \"managed\" ON (\"managed\".\"manager_id\" = \"users\".\"id\")"
99+
"INNER JOIN (\"users\") AS \"managers\" ON (\"managers\".\"id\" = \"users\".\"manager_id\") " +
100+
"INNER JOIN (\"users\") AS \"managed\" ON (\"managed\".\"manager_id\" = \"users\".\"id\")"
101101
ExpectExecutions(db, [SQL: 1]) { _ in for _ in middleManagers {} }
102102
}
103103

@@ -112,7 +112,7 @@ class QueryTests: XCTestCase {
112112
.join(managers, on: managers[id] == users[manager_id])
113113

114114
let SQL = "SELECT \"users\".*, \"managers\".* FROM \"users\" " +
115-
"INNER JOIN \"users\" AS \"managers\" " +
115+
"INNER JOIN (\"users\") AS \"managers\" " +
116116
"ON (\"managers\".\"id\" = \"users\".\"manager_id\")"
117117
ExpectExecutions(db, [SQL: 1]) { _ in for row in query { println(row) } }
118118
}
@@ -265,7 +265,7 @@ class QueryTests: XCTestCase {
265265

266266
func test_alias_compilesAliasInSelectClause() {
267267
let managers = users.alias("managers")
268-
var SQL = "SELECT * FROM \"users\" AS \"managers\""
268+
var SQL = "SELECT * FROM (\"users\") AS \"managers\""
269269
ExpectExecutions(db, [SQL: 1]) { _ in for _ in managers {} }
270270
}
271271

@@ -279,11 +279,11 @@ class QueryTests: XCTestCase {
279279

280280
func test_subscript_withAliasAndExpression_returnsAliasedExpression() {
281281
let managers = users.alias("managers")
282-
ExpectExecution(db, "SELECT \"managers\".\"admin\" FROM \"users\" AS \"managers\"", managers.select(managers[admin]))
283-
ExpectExecution(db, "SELECT \"managers\".\"salary\" FROM \"users\" AS \"managers\"", managers.select(managers[salary]))
284-
ExpectExecution(db, "SELECT \"managers\".\"age\" FROM \"users\" AS \"managers\"", managers.select(managers[age]))
285-
ExpectExecution(db, "SELECT \"managers\".\"email\" FROM \"users\" AS \"managers\"", managers.select(managers[email]))
286-
ExpectExecution(db, "SELECT \"managers\".* FROM \"users\" AS \"managers\"", managers.select(managers[*]))
282+
ExpectExecution(db, "SELECT \"managers\".\"admin\" FROM (\"users\") AS \"managers\"", managers.select(managers[admin]))
283+
ExpectExecution(db, "SELECT \"managers\".\"salary\" FROM (\"users\") AS \"managers\"", managers.select(managers[salary]))
284+
ExpectExecution(db, "SELECT \"managers\".\"age\" FROM (\"users\") AS \"managers\"", managers.select(managers[age]))
285+
ExpectExecution(db, "SELECT \"managers\".\"email\" FROM (\"users\") AS \"managers\"", managers.select(managers[email]))
286+
ExpectExecution(db, "SELECT \"managers\".* FROM (\"users\") AS \"managers\"", managers.select(managers[*]))
287287
}
288288

289289
func test_SQL_compilesProperly() {
@@ -300,7 +300,7 @@ class QueryTests: XCTestCase {
300300
.limit(1, offset: 2)
301301

302302
let SQL = "SELECT \"users\".\"email\", count(\"users\".\"age\") FROM \"users\" " +
303-
"LEFT OUTER JOIN \"users\" AS \"managers\" " +
303+
"LEFT OUTER JOIN (\"users\") AS \"managers\" " +
304304
"ON ((\"managers\".\"id\" = \"users\".\"manager_id\") AND (\"managers\".\"admin\" = 1)) " +
305305
"WHERE \"users\".\"age\" BETWEEN 21 AND 32 " +
306306
"GROUP BY \"users\".\"age\" HAVING (count(\"users\".\"age\") > 1) " +

SQLite/Expression.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ public struct Expression<T> {
116116
return self
117117
}
118118

119+
internal var unaliased: Expression {
120+
return original.map { Expression($0.expression) } ?? self
121+
}
122+
119123
internal func reverse() -> Expression {
120124
var expression = self
121125
expression.ascending = expression.ascending.map(!) ?? false

SQLite/Query.swift

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public struct Query {
2929
internal var database: Database
3030

3131
internal init(_ database: Database, _ tableName: String) {
32+
(self.database, self.tableName) = (database, Expression(tableName))
33+
}
34+
35+
private init(_ database: Database, _ tableName: Expression<()>) {
3236
(self.database, self.tableName) = (database, tableName)
3337
}
3438

@@ -50,17 +54,16 @@ public struct Query {
5054

5155
private var columns: [Expressible] = [Expression<()>(literal: "*")]
5256
private var distinct: Bool = false
53-
internal var tableName: String
54-
private var alias: String?
57+
internal var tableName: Expression<()>
5558
private var joins: [(type: JoinType, table: Query, condition: Expression<Bool>)] = []
5659
private var filter: Expression<Bool>?
5760
private var group: Expressible?
5861
private var order = [Expressible]()
5962
private var limit: (to: Int, offset: Int?)? = nil
6063

61-
public func alias(alias: String?) -> Query {
64+
public func alias(alias: String) -> Query {
6265
var query = self
63-
query.alias = alias
66+
query.tableName = query.tableName.alias(alias)
6467
return query
6568
}
6669

@@ -293,7 +296,7 @@ public struct Query {
293296
/// :returns: A column expression namespaced with the query’s table name or
294297
/// alias.
295298
public func namespace<V>(column: Expression<V>) -> Expression<V> {
296-
return Expression(literal: "\(quote(identifier: alias ?? tableName)).\(column.SQL)", column.bindings)
299+
return Expression(.join(".", [tableName, column]))
297300
}
298301

299302
// FIXME: rdar://18673897 // ... subscript<T>(expression: Expression<V>) -> Expression<V>
@@ -361,7 +364,7 @@ public struct Query {
361364
private func insertStatement(values: [Setter], or: OnConflict? = nil) -> Statement {
362365
var insertClause = "INSERT"
363366
if let or = or { insertClause = "\(insertClause) OR \(or.rawValue)" }
364-
var expressions: [Expressible] = [Expression<()>(literal: "\(insertClause) INTO \(quote(identifier: tableName))")]
367+
var expressions: [Expressible] = [Expression<()>(literal: "\(insertClause) INTO \(tableName.unaliased.SQL)")]
365368
let (c, v) = (Expression<()>.join(", ", values.map { $0.0 }), Expression<()>.join(", ", values.map { $0.1 }))
366369
expressions.append(Expression<()>(literal: "(\(c.SQL)) VALUES (\(v.SQL))", c.bindings + v.bindings))
367370
whereClause.map(expressions.append)
@@ -370,15 +373,15 @@ public struct Query {
370373
}
371374

372375
private func updateStatement(values: [Setter]) -> Statement {
373-
var expressions: [Expressible] = [Expression<()>(literal: "UPDATE \(quote(identifier: tableName)) SET")]
376+
var expressions: [Expressible] = [Expression<()>(literal: "UPDATE \(tableName.unaliased.SQL) SET")]
374377
expressions.append(Expression<()>.join(", ", values.map { Expression<()>.join(" = ", [$0, $1]) }))
375378
whereClause.map(expressions.append)
376379
let expression = Expression<()>.join(" ", expressions)
377380
return database.prepare(expression.SQL, expression.bindings)
378381
}
379382

380383
private var deleteStatement: Statement {
381-
var expressions: [Expressible] = [Expression<()>(literal: "DELETE FROM \(quote(identifier: tableName))")]
384+
var expressions: [Expressible] = [Expression<()>(literal: "DELETE FROM \(tableName.unaliased.SQL)")]
382385
whereClause.map(expressions.append)
383386
let expression = Expression<()>.join(" ", expressions)
384387
return database.prepare(expression.SQL, expression.bindings)
@@ -390,14 +393,14 @@ public struct Query {
390393
var expressions: [Expressible] = [Expression<()>(literal: "SELECT")]
391394
if distinct { expressions.append(Expression<()>(literal: "DISTINCT")) }
392395
expressions.append(Expression<()>.join(", ", columns.map { $0.expression.aliased }))
393-
expressions.append(Expression<()>(literal: "FROM \(self)"))
396+
expressions.append(Expression<()>(literal: "FROM \(tableName.aliased.SQL)"))
394397
return Expression<()>.join(" ", expressions)
395398
}
396399

397400
private var joinClause: Expressible? {
398401
if joins.count == 0 { return nil }
399402
return Expression<()>.join(" ", joins.map { type, table, condition in
400-
Expression<()>(literal: "\(type.rawValue) JOIN \(table) ON \(condition.SQL)", condition.bindings)
403+
Expression<()>(literal: "\(type.rawValue) JOIN \(table.tableName.aliased.SQL) ON \(condition.SQL)", condition.bindings)
401404
})
402405
}
403406

@@ -473,7 +476,7 @@ public struct Query {
473476

474477
public func insert(query: Query) -> (changes: Int?, statement: Statement) {
475478
let expression = query.selectExpression
476-
let statement = database.run("INSERT INTO \(quote(identifier: tableName)) \(expression.SQL)", expression.bindings)
479+
let statement = database.run("INSERT INTO \(tableName.unaliased.SQL) \(expression.SQL)", expression.bindings)
477480
return (statement.failed ? nil : database.lastChanges, statement)
478481
}
479482

@@ -482,7 +485,7 @@ public struct Query {
482485
public func insert() -> Statement { return insert().statement }
483486

484487
public func insert() -> (id: Int64?, statement: Statement) {
485-
let statement = database.run("INSERT INTO \(quote(identifier: tableName)) DEFAULT VALUES")
488+
let statement = database.run("INSERT INTO \(tableName.unaliased.SQL) DEFAULT VALUES")
486489
return (statement.failed ? nil : database.lastId, statement)
487490
}
488491

@@ -827,8 +830,8 @@ public struct QueryGenerator: GeneratorType {
827830

828831
func expandGlob(namespace: Bool) -> Query -> () {
829832
return { table in
830-
var names = self.query.database[table.tableName].selectStatement.columnNames.map { quote(identifier: $0) }
831-
if namespace { names = names.map { "\(quote(identifier: table.alias ?? table.tableName)).\($0)" } }
833+
var names = Query(self.query.database, self.query.tableName.unaliased).selectStatement.columnNames.map { quote(identifier: $0) }
834+
if namespace { names = names.map { "\(table.tableName.SQL).\($0)" } }
832835
for name in names { columnNames[name] = idx++ }
833836
}
834837
}
@@ -837,7 +840,7 @@ public struct QueryGenerator: GeneratorType {
837840
let tables = [self.query] + self.query.joins.map { $0.table }
838841
if let tableName = tableName {
839842
for table in tables {
840-
if quote(identifier: table.alias ?? table.tableName) == tableName {
843+
if table.tableName.SQL == tableName {
841844
expandGlob(true)(table)
842845
continue column
843846
}
@@ -867,8 +870,7 @@ public struct QueryGenerator: GeneratorType {
867870
extension Query: Printable {
868871

869872
public var description: String {
870-
if let alias = alias { return "\(quote(identifier: tableName)) AS \(quote(identifier: alias))" }
871-
return quote(identifier: tableName)
873+
return tableName.SQL
872874
}
873875

874876
}

SQLite/Schema.swift

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,19 @@ public extension Database {
3232
) -> Statement {
3333
var builder = SchemaBuilder(table)
3434
block(builder)
35-
let create = createSQL("TABLE", temporary, false, ifNotExists, table.tableName)
35+
let create = createSQL("TABLE", temporary, false, ifNotExists, table.tableName.unaliased.SQL)
3636
let columns = Expression<()>.join(", ", builder.columns).compile()
3737
return run("\(create) (\(columns))")
3838
}
3939
4040
public func create(#table: Query, temporary: Bool = false, ifNotExists: Bool = false, from: Query) -> Statement {
41-
let create = createSQL("TABLE", temporary, false, ifNotExists, table.tableName)
41+
let create = createSQL("TABLE", temporary, false, ifNotExists, table.tableName.unaliased.SQL)
4242
let expression = from.selectExpression
4343
return run("\(create) AS \(expression.SQL)", expression.bindings)
4444
}
4545
4646
public func rename(#table: Query, to tableName: String) -> Statement {
47-
return run("ALTER TABLE \(quote(identifier: table.tableName)) RENAME TO \(quote(identifier: tableName))")
47+
return run("ALTER TABLE \(table.tableName.unaliased.SQL) RENAME TO \(quote(identifier: tableName))")
4848
}
4949
5050
public func alter<V: Value>(
@@ -103,11 +103,11 @@ public extension Database {
103103
}
104104
105105
private func alter(table: Query, _ definition: Expressible) -> Statement {
106-
return run("ALTER TABLE \(quote(identifier: table.tableName)) ADD COLUMN \(definition.expression.compile())")
106+
return run("ALTER TABLE \(table.tableName.unaliased.SQL) ADD COLUMN \(definition.expression.compile())")
107107
}
108108
109109
public func drop(#table: Query, ifExists: Bool = false) -> Statement {
110-
return run(dropSQL("TABLE", ifExists, table.tableName))
110+
return run(dropSQL("TABLE", ifExists, table.tableName.unaliased.SQL))
111111
}
112112
113113
public func create(
@@ -116,32 +116,33 @@ public extension Database {
116116
ifNotExists: Bool = false,
117117
on columns: Expressible...
118118
) -> Statement {
119-
let create = createSQL("INDEX", false, unique, ifNotExists, indexName(table, on: columns))
119+
let tableName = table.tableName.unaliased.SQL
120+
let create = createSQL("INDEX", false, unique, ifNotExists, indexName(tableName, on: columns))
120121
let joined = Expression<()>.join(", ", columns.map { $0.expression.ordered })
121-
return run("\(create) ON \(quote(identifier: table.tableName)) (\(joined.compile()))")
122+
return run("\(create) ON \(tableName) (\(joined.compile()))")
122123
}
123124
124125
public func drop(index table: Query, ifExists: Bool = false, on columns: Expressible...) -> Statement {
125-
return run(dropSQL("INDEX", ifExists, indexName(table, on: columns)))
126+
return run(dropSQL("INDEX", ifExists, indexName(table.tableName.unaliased.SQL, on: columns)))
126127
}
127128
128-
private func indexName(table: Query, on columns: [Expressible]) -> String {
129-
let string = join(" ", ["index", table.tableName, "on"] + columns.map { $0.expression.SQL })
130-
return reduce(string, "") { underscored, character in
129+
private func indexName(table: String, on columns: [Expressible]) -> String {
130+
let string = join(" ", ["index", table, "on"] + columns.map { $0.expression.SQL })
131+
return quote(identifier: reduce(string, "") { underscored, character in
131132
if character == "\"" { return underscored }
132133
if "A"..."Z" ~= character || "a"..."z" ~= character { return underscored + String(character) }
133134
return underscored + "_"
134-
}
135+
})
135136
}
136137
137138
public func create(#view: Query, temporary: Bool = false, ifNotExists: Bool = false, from: Query) -> Statement {
138-
let create = createSQL("VIEW", temporary, false, ifNotExists, view.tableName)
139+
let create = createSQL("VIEW", temporary, false, ifNotExists, view.tableName.unaliased.SQL)
139140
let expression = from.selectExpression
140141
return run("\(create) AS \(expression.SQL)", expression.bindings)
141142
}
142143
143144
public func drop(#view: Query, ifExists: Bool = false) -> Statement {
144-
return run(dropSQL("VIEW", ifExists, view.tableName))
145+
return run(dropSQL("VIEW", ifExists, view.tableName.unaliased.SQL))
145146
}
146147
147148
}
@@ -246,7 +247,7 @@ public final class SchemaBuilder {
246247
name,
247248
unique: unique,
248249
check: check,
249-
references: Expression(literal: references.tableName)
250+
references: Expression(references.tableName)
250251
)
251252
}
252253
@@ -471,13 +472,13 @@ private func createSQL(
471472
if unique { parts.append("UNIQUE") }
472473
parts.append(type)
473474
if ifNotExists { parts.append("IF NOT EXISTS") }
474-
parts.append(quote(identifier: name))
475+
parts.append(name)
475476
return Swift.join(" ", parts)
476477
}
477478

478479
private func dropSQL(type: String, ifExists: Bool, name: String) -> String {
479480
var parts: [String] = ["DROP \(type)"]
480481
if ifExists { parts.append("IF EXISTS") }
481-
parts.append(quote(identifier: name))
482+
parts.append(name)
482483
return Swift.join(" ", parts)
483484
}

0 commit comments

Comments
 (0)