|
1 |
| - |
2 | 1 | /// SQLQueryGenerator is able to generate an SQL SELECT query.
|
3 | 2 | struct SQLQueryGenerator: Refinable {
|
4 | 3 | fileprivate private(set) var relation: SQLQualifiedRelation
|
@@ -627,7 +626,7 @@ private struct SQLQualifiedJoin: Refinable {
|
627 | 626 |
|
628 | 627 | enum Target {
|
629 | 628 | case all
|
630 |
| - case subRelation(SQLRelation) |
| 629 | + case first(SQLRelation) |
631 | 630 | }
|
632 | 631 |
|
633 | 632 | var kind: Kind
|
@@ -667,10 +666,8 @@ private struct SQLQualifiedJoin: Refinable {
|
667 | 666 | .unfiltered()
|
668 | 667 | .unordered()
|
669 | 668 |
|
670 |
| - let subRelation = relation |
671 |
| - |
672 | 669 | self.relation = SQLQualifiedRelation(outerRelation)
|
673 |
| - self.target = .subRelation(subRelation) |
| 670 | + self.target = .first(relation) |
674 | 671 | } else {
|
675 | 672 | self.relation = SQLQualifiedRelation(relation)
|
676 | 673 | self.target = .all
|
@@ -709,32 +706,43 @@ private struct SQLQualifiedJoin: Refinable {
|
709 | 706 | case .leftJoin:
|
710 | 707 | allowsInnerJoin = false
|
711 | 708 | }
|
| 709 | + |
| 710 | + // JOIN table... |
712 | 711 | sql += try "\(kind.rawValue) \(relation.source.sql(db, &context))"
|
713 | 712 |
|
714 | 713 | let rightAlias = relation.sourceAlias
|
715 | 714 | switch target {
|
716 | 715 | case .all:
|
717 |
| - let filters = try condition.expressions(db, leftAlias: leftAlias, rightAlias: rightAlias) |
718 |
| - + relation.filtersPromise.resolve(db) |
| 716 | + // ... ON <join conditions> AND <other filters> |
| 717 | + var filters = try condition.expressions(db, leftAlias: leftAlias) |
| 718 | + filters += try relation.filtersPromise.resolve(db) |
719 | 719 | if filters.isEmpty == false {
|
720 |
| - sql += " ON \(filters.joined(operator: .and).expressionSQL(&context, wrappedInParenthesis: false))" |
| 720 | + let filterSQL = filters |
| 721 | + .joined(operator: .and) |
| 722 | + .qualifiedExpression(with: rightAlias) |
| 723 | + .expressionSQL(&context, wrappedInParenthesis: false) |
| 724 | + sql += " ON \(filterSQL)" |
721 | 725 | }
|
722 |
| - case let .subRelation(subRelation): |
| 726 | + case var .first(subRelation): |
| 727 | + // Subquery: SELECT id ... |
723 | 728 | guard let primaryKey = try subRelation.primaryKeyExpression(db) else {
|
724 |
| - fatalError("Not implemented") |
| 729 | + fatalError("Not implemented: support for WITHOUT ROWID optimization") |
725 | 730 | }
|
726 |
| - let subAlias = TableAlias() |
727 |
| - let filters = try condition.expressions(db, leftAlias: leftAlias, rightAlias: subAlias) |
728 |
| - let subRelation = subRelation |
729 |
| - .qualified(with: subAlias) |
730 |
| - .selectOnly([primaryKey]) |
731 |
| - .map(\.filtersPromise) { $0.flatMap { DatabasePromise(value: filters + $0) } } |
| 731 | + subRelation = subRelation.select([primaryKey]) |
| 732 | + |
| 733 | + // Subquery: ... WHERE <condition filters> AND <other filters> |
| 734 | + let filters = try condition.expressions(db, leftAlias: leftAlias) |
| 735 | + subRelation = subRelation.prependingFilters(filters) |
| 736 | + |
| 737 | + // Subquery: ... LIMIT 1 |
732 | 738 | let subQuery = SQLQuery(relation: subRelation, limit: SQLLimit(limit: 1, offset: nil))
|
733 |
| - let subQueryGenerator = SQLQueryGenerator(subQuery) |
734 | 739 |
|
| 740 | + // ... ON id = (SELECT id FROM table WHERE <condition filters> AND <other filters> LIMIT 1) |
735 | 741 | sql += " ON "
|
736 | 742 | sql += rightAlias[primaryKey].expressionSQL(&context, wrappedInParenthesis: false)
|
737 |
| - sql += try " = (" + subQueryGenerator.sql(db, &context) + ")" |
| 743 | + sql += " = (" |
| 744 | + sql += try SQLQueryGenerator(subQuery).sql(db, &context) |
| 745 | + sql += ")" |
738 | 746 | }
|
739 | 747 |
|
740 | 748 | for (_, join) in relation.joins {
|
|
0 commit comments