From 68ce7ecaf4899df7807b3c24bb2593e744368eb7 Mon Sep 17 00:00:00 2001 From: Stephan Heilner Date: Thu, 31 May 2018 15:14:02 -0600 Subject: [PATCH 1/3] Fixed bug not allowing columns from multiple tables in the .select --- SQLite.xcodeproj/project.pbxproj | 8 +++++ Sources/SQLite/Typed/Query.swift | 1 - Tests/SQLiteTests/SelectTests.swift | 45 +++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 Tests/SQLiteTests/SelectTests.swift diff --git a/SQLite.xcodeproj/project.pbxproj b/SQLite.xcodeproj/project.pbxproj index 30a40214..a591aad3 100644 --- a/SQLite.xcodeproj/project.pbxproj +++ b/SQLite.xcodeproj/project.pbxproj @@ -108,6 +108,9 @@ 49EB68C51F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; }; 49EB68C61F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; }; 49EB68C71F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; }; + D4DB368C20C09CFB00D5A58E /* SelectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4DB368A20C09C9B00D5A58E /* SelectTests.swift */; }; + D4DB368D20C09CFC00D5A58E /* SelectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4DB368A20C09C9B00D5A58E /* SelectTests.swift */; }; + D4DB368E20C09CFD00D5A58E /* SelectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4DB368A20C09C9B00D5A58E /* SelectTests.swift */; }; EE247AD71C3F04ED00AE3E12 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; EE247ADE1C3F04ED00AE3E12 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE247AD31C3F04ED00AE3E12 /* SQLite.framework */; }; EE247B031C3F06E900AE3E12 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; }; @@ -228,6 +231,7 @@ 3D67B3E51DB2469200A4F4C6 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS3.0.sdk/usr/lib/libsqlite3.tbd; sourceTree = DEVELOPER_DIR; }; 49EB68C31F7B3CB400D89D40 /* Coding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coding.swift; sourceTree = ""; }; A121AC451CA35C79005A31D1 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D4DB368A20C09C9B00D5A58E /* SelectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectTests.swift; sourceTree = ""; }; EE247AD31C3F04ED00AE3E12 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EE247AD61C3F04ED00AE3E12 /* SQLite.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLite.h; sourceTree = ""; }; EE247AD81C3F04ED00AE3E12 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -418,6 +422,7 @@ 19A17B93B48B5560E6E51791 /* Fixtures.swift */, 19A175C1F9CB3BBAB8FCEC7B /* RowTests.swift */, 19A1729B75C33F9A0B9A89C1 /* DateAndTimeFunctionTests.swift */, + D4DB368A20C09C9B00D5A58E /* SelectTests.swift */, ); name = SQLiteTests; path = Tests/SQLiteTests; @@ -847,6 +852,7 @@ 19A17F60B685636D1F83C2DD /* Fixtures.swift in Sources */, 19A1785195182AF8731A8BDA /* RowTests.swift in Sources */, 19A1769C1F3A7542BECF50FF /* DateAndTimeFunctionTests.swift in Sources */, + D4DB368E20C09CFD00D5A58E /* SelectTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -935,6 +941,7 @@ 19A17408007B182F884E3A53 /* Fixtures.swift in Sources */, 19A1720B67ED13E6150C6A3D /* RowTests.swift in Sources */, 19A17C80076860CF7751A056 /* DateAndTimeFunctionTests.swift in Sources */, + D4DB368C20C09CFB00D5A58E /* SelectTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -993,6 +1000,7 @@ 19A1709C3E7A406E62293B2A /* Fixtures.swift in Sources */, 19A171967CC511C4F6F773C9 /* RowTests.swift in Sources */, 19A172EB202970561E5C4245 /* DateAndTimeFunctionTests.swift in Sources */, + D4DB368D20C09CFC00D5A58E /* SelectTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/SQLite/Typed/Query.swift b/Sources/SQLite/Typed/Query.swift index f6ef6df8..7ec5e581 100644 --- a/Sources/SQLite/Typed/Query.swift +++ b/Sources/SQLite/Typed/Query.swift @@ -963,7 +963,6 @@ extension Connection { try expandGlob(true)(q) continue column } - throw QueryError.noSuchTable(name: namespace) } throw QueryError.noSuchTable(name: namespace) } diff --git a/Tests/SQLiteTests/SelectTests.swift b/Tests/SQLiteTests/SelectTests.swift new file mode 100644 index 00000000..bca01092 --- /dev/null +++ b/Tests/SQLiteTests/SelectTests.swift @@ -0,0 +1,45 @@ +import XCTest +@testable import SQLite + +class SelectTests: SQLiteTestCase { + + override func setUp() { + super.setUp() + CreateUsersTable() + CreateUsersDataTable() + } + + func CreateUsersDataTable() { + try! db.execute(""" + CREATE TABLE users_name ( + id INTEGER, + user_id INTEGER REFERENCES users(id), + name TEXT + ) + """ + ) + } + + func test_select_columns_from_multiple_tables() { + let usersData = Table("users_name") + let users = Table("users") + + let name = Expression("name") + let id = Expression("id") + let userID = Expression("user_id") + let email = Expression("email") + + try! InsertUser("Joey") + try! db.run(usersData.insert( + id <- 1, + userID <- 1, + name <- "Joey" + )) + + try! db.prepare(users.select(name, email).join(usersData, on: userID == users[id])).forEach { + XCTAssertEqual($0[name], "Joey") + XCTAssertEqual($0[email], "Joey@example.com") + } + } + +} From c9fe32c5585ae6b081c5f00d2944bea4f1fc44d2 Mon Sep 17 00:00:00 2001 From: Stephan Heilner Date: Tue, 23 Apr 2019 10:12:58 -0600 Subject: [PATCH 2/3] Added alias to select --- SQLite.swift.podspec | 6 ++-- Sources/SQLite/Typed/Expression.swift | 27 ++++++++++-------- Sources/SQLite/Typed/Query.swift | 38 ++++++++++++++++++------- Tests/SQLiteTests/ConnectionTests.swift | 2 +- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/SQLite.swift.podspec b/SQLite.swift.podspec index 712ddc36..fd8dc960 100644 --- a/SQLite.swift.podspec +++ b/SQLite.swift.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "SQLite.swift" - s.version = "0.12.2" - s.summary = "A type-safe, Swift-language layer over SQLite3 for iOS and macOS." + s.version = "0.12.1.1" + s.summary = "A type-safe, Swift-language layer over SQLite3 for iOS and OS X." s.description = <<-DESC SQLite.swift provides compile-time confidence in SQL statement syntax and @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.homepage = "https://github.com/stephencelis/SQLite.swift" s.license = 'MIT' s.author = { "Stephen Celis" => "stephen@stephencelis.com" } - s.source = { :git => "https://github.com/stephencelis/SQLite.swift.git", :tag => s.version.to_s } + s.source = { :git => "https://github.com/stephanheilner/SQLite.swift.git", :tag => s.version.to_s } s.social_media_url = 'https://twitter.com/stephencelis' s.module_name = 'SQLite' diff --git a/Sources/SQLite/Typed/Expression.swift b/Sources/SQLite/Typed/Expression.swift index 76ba04c4..5b5f6eb7 100644 --- a/Sources/SQLite/Typed/Expression.swift +++ b/Sources/SQLite/Typed/Expression.swift @@ -28,15 +28,16 @@ public protocol ExpressionType : Expressible { // extensions cannot have inherit var template: String { get } var bindings: [Binding?] { get } - - init(_ template: String, _ bindings: [Binding?]) + var alias: String? { get } + + init(_ template: String, _ bindings: [Binding?], _ alias: String?) } extension ExpressionType { - public init(literal: String) { - self.init(literal, []) + public init(literal: String, alias: String? = nil) { + self.init(literal, [], alias) } public init(_ identifier: String) { @@ -44,7 +45,7 @@ extension ExpressionType { } public init(_ expression: U) { - self.init(expression.template, expression.bindings) + self.init(expression.template, expression.bindings, expression.alias) } } @@ -56,10 +57,12 @@ public struct Expression : ExpressionType { public var template: String public var bindings: [Binding?] - - public init(_ template: String, _ bindings: [Binding?]) { + public var alias: String? + + public init(_ template: String, _ bindings: [Binding?], _ alias: String? = nil) { self.template = template self.bindings = bindings + self.alias = alias } } @@ -95,7 +98,7 @@ extension Expressible { extension ExpressionType { public var expression: Expression { - return Expression(template, bindings) + return Expression(template, bindings, alias) } public var asc: Expressible { @@ -111,7 +114,7 @@ extension ExpressionType { extension ExpressionType where UnderlyingType : Value { public init(value: UnderlyingType) { - self.init("?", [value.datatypeValue]) + self.init("?", [value.datatypeValue], nil) } } @@ -123,7 +126,7 @@ extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.Wr } public init(value: UnderlyingType.WrappedType?) { - self.init("?", [value?.datatypeValue]) + self.init("?", [value?.datatypeValue], nil) } } @@ -139,9 +142,9 @@ extension Value { public let rowid = Expression("ROWID") public func cast(_ expression: Expression) -> Expression { - return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings) + return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings, expression.alias) } public func cast(_ expression: Expression) -> Expression { - return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings) + return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings, expression.alias) } diff --git a/Sources/SQLite/Typed/Query.swift b/Sources/SQLite/Typed/Query.swift index 7ec5e581..5aa7dc54 100644 --- a/Sources/SQLite/Typed/Query.swift +++ b/Sources/SQLite/Typed/Query.swift @@ -504,12 +504,22 @@ extension QueryType { // MARK: - fileprivate var selectClause: Expressible { - return " ".join([ + let blah = " ".join([ Expression(literal: clauses.select.distinct ? "SELECT DISTINCT" : "SELECT"), - ", ".join(clauses.select.columns), + ", ".join(clauses.select.columns.map { column in + if let alias = column.expression.alias { + return " ".join([ + Expression(literal: column.expression.template.quote()), + Expression(literal: "AS"), + Expression(literal: alias.quote()) + ]) + } + return column + }), Expression(literal: "FROM"), tableName(alias: true) ]) + return blah } fileprivate var joinClause: Expressible? { @@ -852,10 +862,12 @@ public struct Select : ExpressionType { public var template: String public var bindings: [Binding?] + public var alias: String? - public init(_ template: String, _ bindings: [Binding?]) { + public init(_ template: String, _ bindings: [Binding?], _ alias: String? = nil) { self.template = template self.bindings = bindings + self.alias = alias } } @@ -864,10 +876,12 @@ public struct Insert : ExpressionType { public var template: String public var bindings: [Binding?] - - public init(_ template: String, _ bindings: [Binding?]) { + public var alias: String? + + public init(_ template: String, _ bindings: [Binding?], _ alias: String? = nil) { self.template = template self.bindings = bindings + self.alias = alias } } @@ -876,10 +890,12 @@ public struct Update : ExpressionType { public var template: String public var bindings: [Binding?] - - public init(_ template: String, _ bindings: [Binding?]) { + public var alias: String? + + public init(_ template: String, _ bindings: [Binding?], _ alias: String? = nil) { self.template = template self.bindings = bindings + self.alias = alias } } @@ -888,10 +904,12 @@ public struct Delete : ExpressionType { public var template: String public var bindings: [Binding?] - - public init(_ template: String, _ bindings: [Binding?]) { + public var alias: String? + + public init(_ template: String, _ bindings: [Binding?], _ alias: String? = nil) { self.template = template self.bindings = bindings + self.alias = alias } } @@ -972,7 +990,7 @@ extension Connection { continue } - columnNames[each.expression.template] = idx + columnNames[each.expression.alias ?? each.expression.template] = idx idx += 1 } return columnNames diff --git a/Tests/SQLiteTests/ConnectionTests.swift b/Tests/SQLiteTests/ConnectionTests.swift index eab3cf00..6d7cbb11 100644 --- a/Tests/SQLiteTests/ConnectionTests.swift +++ b/Tests/SQLiteTests/ConnectionTests.swift @@ -45,7 +45,7 @@ class ConnectionTests : SQLiteTestCase { let db = try! Connection("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3") XCTAssertEqual("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3", db.description) } - + func test_readonly_returnsFalseOnReadWriteConnections() { XCTAssertFalse(db.readonly) } From 9f650f6ab7a269ff12d701a57893e5fec6e78f5d Mon Sep 17 00:00:00 2001 From: Stephan Heilner Date: Wed, 17 Mar 2021 12:12:13 -0600 Subject: [PATCH 3/3] Bumped version to 0.12.2.2 --- SQLite.swift.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SQLite.swift.podspec b/SQLite.swift.podspec index fd8dc960..17dbaedd 100644 --- a/SQLite.swift.podspec +++ b/SQLite.swift.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "SQLite.swift" - s.version = "0.12.1.1" - s.summary = "A type-safe, Swift-language layer over SQLite3 for iOS and OS X." + s.version = "0.12.2.2" + s.summary = "A type-safe, Swift-language layer over SQLite3 for iOS and macOS." s.description = <<-DESC SQLite.swift provides compile-time confidence in SQL statement syntax and