Skip to content

Commit

Permalink
feat: enable return id after insert (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
EnriqueL8 authored and tunniclm committed Jan 29, 2018
1 parent e1d69d5 commit fb951c6
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 30 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/IBM-Swift/CLibpq.git", .upToNextMinor(from: "0.1.0")),
.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", .upToNextMinor(from: "1.0.0")),
.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand Down
27 changes: 23 additions & 4 deletions Sources/SwiftKueryPostgreSQL/PostgreSQLConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ public class PostgreSQLConnection: Connection {
/// - Parameter onCompletion: The function to be called when the execution of the query has completed.
public func execute(query: Query, parameters: [Any?], onCompletion: @escaping ((QueryResult) -> ())) {
do {
let postgresQuery = try query.build(queryBuilder: queryBuilder)
let postgresQuery = try buildQuery(query)
execute(query: postgresQuery, preparedStatement: nil, with: parameters, onCompletion: onCompletion)
}
catch QueryError.syntaxError(let error) {
Expand All @@ -218,14 +218,14 @@ public class PostgreSQLConnection: Connection {
onCompletion(.error(QueryError.syntaxError("Failed to build the query")))
}
}

/// Execute a query.
///
/// - Parameter query: The query to execute.
/// - Parameter onCompletion: The function to be called when the execution of the query has completed.
public func execute(query: Query, onCompletion: @escaping ((QueryResult) -> ())) {
do {
let postgresQuery = try query.build(queryBuilder: queryBuilder)
let postgresQuery = try buildQuery(query)
execute(query: postgresQuery, preparedStatement: nil, with: [Any?](), onCompletion: onCompletion)
}
catch QueryError.syntaxError(let error) {
Expand Down Expand Up @@ -268,7 +268,7 @@ public class PostgreSQLConnection: Connection {
/// - Returns: The prepared statement.
/// - Throws: QueryError.syntaxError if query build fails, or a database error if it fails to prepare statement.
public func prepareStatement(_ query: Query) throws -> PreparedStatement {
let postgresQuery = try query.build(queryBuilder: queryBuilder)
let postgresQuery = try buildQuery(query)
return try prepareStatement(postgresQuery)
}

Expand Down Expand Up @@ -479,6 +479,7 @@ public class PostgreSQLConnection: Connection {
if let error = String(validatingUTF8: PQerrorMessage(connection)) {
message += " Error: \(error)."
}

PQclear(result)
onCompletion(.error(QueryError.databaseError(message)))
return
Expand All @@ -491,4 +492,22 @@ public class PostgreSQLConnection: Connection {
PQclear(result)
onCompletion(.successNoData)
}

private func buildQuery(_ query: Query) throws -> String {
var postgresQuery = try query.build(queryBuilder: queryBuilder)

if let insertQuery = query as? Insert, insertQuery.returnID {
let columns = insertQuery.table.columns.filter { $0.isPrimaryKey && $0.autoIncrement }

if (insertQuery.suffix == nil && columns.count == 1) {
let insertQueryReturnID = insertQuery.suffix("Returning " + columns[0].name)
postgresQuery = try insertQueryReturnID.build(queryBuilder: queryBuilder)
}

if (insertQuery.suffix != nil) {
throw QueryError.syntaxError("Suffix for query already set, could not add Returning suffix")
}
}
return postgresQuery
}
}
96 changes: 71 additions & 25 deletions Tests/SwiftKueryPostgreSQLTests/TestInsert.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/**
Copyright IBM Corporation 2016, 2017
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -22,60 +22,70 @@ import SwiftKuery
#if os(Linux)
let tableInsert = "tableInsertLinux"
let tableInsert2 = "tableInsert2Linux"
let tableInsert3 = "tableInsert3Linux"
#else
let tableInsert = "tableInsertOSX"
let tableInsert2 = "tableInsert2OSX"
let tableInsert3 = "tableInsert3OSX"
#endif

class TestInsert: XCTestCase {

static var allTests: [(String, (TestInsert) -> () throws -> Void)] {
return [
("testInsert", testInsert),
("testInsertID", testInsertID)
]
}

class MyTable : Table {
let a = Column("a")
let a = Column("a", autoIncrement: true, primaryKey: true)
let b = Column("b")

let tableName = tableInsert
}

class MyTable2 : Table {
let a = Column("a")
let b = Column("b")

let tableName = tableInsert2
}

class MyTable3 : Table {
let a = Column("a", autoIncrement: true, primaryKey: true)
let b = Column("b")

let tableName = tableInsert3
}
func testInsert() {
let t = MyTable()
let t2 = MyTable2()

let pool = CommonUtils.sharedInstance.getConnectionPool()
performTest(asyncTasks: { expectation in

guard let connection = pool.getConnection() else {
XCTFail("Failed to get connection")
return
}

cleanUp(table: t.tableName, connection: connection) { result in
cleanUp(table: t2.tableName, connection: connection) { result in

executeRawQuery("CREATE TABLE " + t.tableName + " (a varchar(40), b integer)", connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "CREATE TABLE failed")
XCTAssertNil(result.asError, "Error in CREATE TABLE: \(result.asError!)")

executeRawQuery("CREATE TABLE " + t2.tableName + " (a varchar(40), b integer)", connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "CREATE TABLE failed")
XCTAssertNil(result.asError, "Error in CREATE TABLE: \(result.asError!)")

let i1 = Insert(into: t, values: "apple", 10)
executeQuery(query: i1, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "INSERT failed")
XCTAssertNil(result.asError, "Error in INSERT: \(result.asError!)")

let i2 = Insert(into: t, valueTuples: (t.a, "apricot"), (t.b, "3"))
.suffix("RETURNING *")
executeQuery(query: i2, connection: connection) { result, rows in
Expand All @@ -89,7 +99,7 @@ class TestInsert: XCTestCase {
XCTAssertEqual(resultSet.titles[1], "b", "Wrong column name: \(resultSet.titles[1]) instead of b")
XCTAssertEqual(rows![0][0]! as! String, "apricot", "Wrong value in row 0 column 0")
XCTAssertEqual(rows![0][1]! as! Int32, 3, "Wrong value in row 1 column 0")

let i3 = Insert(into: t, columns: [t.a, t.b], values: ["banana", 17])
.suffix("RETURNING b")
executeQuery(query: i3, connection: connection) { result, rows in
Expand All @@ -102,7 +112,7 @@ class TestInsert: XCTestCase {
XCTAssertEqual(resultSet.titles[0], "b", "Wrong column name: \(resultSet.titles[0]) instead of b")
XCTAssertEqual(resultSet.titles.count, 1, "Wrong number of columns: \(resultSet.titles.count) instead of 1")
XCTAssertEqual(rows![0][0]! as! Int32, 17, "Wrong value in row 0 column 0")

let i4 = Insert(into: t, rows: [["apple", 17], ["banana", -7], ["banana", 27]])
.suffix("RETURNING b")
executeQuery(query: i4, connection: connection) { result, rows in
Expand All @@ -111,7 +121,7 @@ class TestInsert: XCTestCase {
XCTAssertNotNil(result.asResultSet, "INSERT returned no rows")
XCTAssertNotNil(rows, "INSERT returned no rows")
XCTAssertEqual(rows!.count, 3, "INSERT returned wrong number of rows: \(rows!.count) instead of 3")

let i5 = Insert(into: t, rows: [["apple", 5], ["banana", 10], ["banana", 3]])
.suffix("RETURNING b, a")
executeQuery(query: i5, connection: connection) { result, rows in
Expand All @@ -121,27 +131,26 @@ class TestInsert: XCTestCase {
let resultSet = result.asResultSet!
XCTAssertEqual(rows!.count, 3, "INSERT returned wrong number of rows: \(rows!.count) instead of 3")
XCTAssertEqual(resultSet.titles.count, 2, "Wrong number of columns: \(resultSet.titles.count) instead of 2")

let i6 = Insert(into: t2, Select(from: t).where(t.a == "apple"))
.suffix("RETURNING *")
executeQuery(query: i6, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "INSERT failed")
XCTAssertNil(result.asError, "Error in INSERT: \(result.asError!)")
XCTAssertNil(result.asError, "Error in INSERT: \(result.asError!)")
XCTAssertNotNil(rows, "INSERT returned no rows")
let resultSet = result.asResultSet!
XCTAssertEqual(rows!.count, 3, "INSERT returned wrong number of rows: \(rows!.count) instead of 3")
XCTAssertEqual(resultSet.titles.count, 2, "Wrong number of columns: \(resultSet.titles.count) instead of 2")

let s1 = Select(from: t)
executeQuery(query: s1, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "SELECT failed")
XCTAssertNil(result.asError, "Error in SELECT: \(result.asError!)")
XCTAssertNotNil(rows, "SELECT returned no rows")
XCTAssertEqual(rows!.count, 9, "INSERT returned wrong number of rows: \(rows!.count) instead of 9")
let drop = Raw(query: "DROP TABLE", table: t)
executeQuery(query: drop, connection: connection) { result, rows in

let dropT = Raw(query: "DROP TABLE", table: t)
executeQuery(query: dropT, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "DROP TABLE failed")
XCTAssertNil(result.asError, "Error in DELETE: \(result.asError!)")
}
Expand All @@ -159,4 +168,41 @@ class TestInsert: XCTestCase {
expectation.fulfill()
})
}

func testInsertID() {
let t3 = MyTable3()

let pool = CommonUtils.sharedInstance.getConnectionPool()
performTest(asyncTasks: { expectation in

guard let connection = pool.getConnection() else {
XCTFail("Failed to get connection")
return
}

cleanUp(table: t3.tableName, connection: connection) { result in
executeRawQuery("CREATE TABLE " + t3.tableName + " (a SERIAL PRIMARY KEY, b integer)", connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "CREATE TABLE failed")
XCTAssertNil(result.asError, "Error in CREATE TABLE: \(result.asError!)")
let i7 = Insert(into: t3, valueTuples: [(t3.b, 5)], returnID: true)
executeQuery(query: i7, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "INSERT failed")
XCTAssertNil(result.asError, "Error in INSERT: \(result.asError!)")
XCTAssertNotNil(result.asResultSet, "INSERT returned no rows")
XCTAssertNotNil(rows, "INSERT returned no rows")
let resultSet = result.asResultSet!
XCTAssertEqual(rows!.count, 1, "INSERT returned wrong number of rows: \(rows!.count) instead of 1")
XCTAssertEqual(resultSet.titles.count, 1, "Wrong number of columns: \(resultSet.titles.count) instead of 1")

let dropT3 = Raw(query: "DROP TABLE", table: t3)
executeQuery(query: dropT3, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "DROP TABLE failed")
XCTAssertNil(result.asError, "Error in DELETE: \(result.asError!)")
}
}
}
}
expectation.fulfill()
})
}
}

0 comments on commit fb951c6

Please sign in to comment.