Skip to content

Commit

Permalink
Enhance support for nil values (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
kilnerm committed May 1, 2019
1 parent 2608e55 commit c56b52e
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 36 deletions.
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ let package = Package(
)
],
dependencies: [
.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", from: "3.0.0"),
//.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", from: "3.1.0"),
.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", .branch("master")),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand Down
3 changes: 2 additions & 1 deletion Package@swift-4.0.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ 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", from: "3.0.0"),
//.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", from: "3.1.0"),
.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", .branch("master")),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand Down
3 changes: 2 additions & 1 deletion Package@swift-4.1.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ 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", from: "3.0.0"),
//.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", from: "3.1.0"),
.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", .branch("master")),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand Down
3 changes: 2 additions & 1 deletion Package@swift-4.2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ let package = Package(
)
],
dependencies: [
.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", from: "3.0.0"),
//.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", from: "3.1.0"),
.package(url: "https://github.com/IBM-Swift/Swift-Kuery.git", .branch("master")),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand Down
31 changes: 3 additions & 28 deletions Sources/SwiftKueryPostgreSQL/PostgreSQLConnection.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
Copyright IBM Corporation 2016, 2017, 2018
Copyright IBM Corporation 2016, 2017, 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -649,14 +649,8 @@ class PostgreSQLColumnBuilder: ColumnCreator {
if column.isUnique {
result += " UNIQUE"
}
if let defaultValue = column.defaultValue {
var packedType: String
do {
packedType = try packType(defaultValue, queryBuilder: queryBuilder)
} catch {
return nil
}
result += " DEFAULT " + packedType
if let defaultValue = getDefaultValue(for: column, queryBuilder: queryBuilder) {
result += " DEFAULT " + defaultValue
}
if let checkExpression = column.checkExpression {
result += checkExpression.contains(column.name) ? " CHECK (" + checkExpression.replacingOccurrences(of: column.name, with: "\"\(column.name)\"") + ")" : " CHECK (" + checkExpression + ")"
Expand All @@ -679,23 +673,4 @@ class PostgreSQLColumnBuilder: ColumnCreator {
return nil
}
}

func packType(_ item: Any, queryBuilder: QueryBuilder) throws -> String {
switch item {
case let val as String:
return "'\(val)'"
case let val as Bool:
return val ? queryBuilder.substitutions[QueryBuilder.QuerySubstitutionNames.booleanTrue.rawValue]
: queryBuilder.substitutions[QueryBuilder.QuerySubstitutionNames.booleanFalse.rawValue]
case let val as Parameter:
return try val.build(queryBuilder: queryBuilder)
case let value as Date:
if let dateFormatter = queryBuilder.dateFormatter {
return dateFormatter.string(from: value)
}
return "'\(String(describing: value))'"
default:
return String(describing: item)
}
}
}
58 changes: 56 additions & 2 deletions Tests/SwiftKueryPostgreSQLTests/TestInsert.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
Copyright IBM Corporation 2016, 2017
Copyright IBM Corporation 2016, 2017, 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -23,18 +23,21 @@ import SwiftKuery
let tableInsert = "tableInsertLinux"
let tableInsert2 = "tableInsert2Linux"
let tableInsert3 = "tableInsert3Linux"
let tableInsert4 = "tableInsert4Linux"
#else
let tableInsert = "tableInsertOSX"
let tableInsert2 = "tableInsert2OSX"
let tableInsert3 = "tableInsert3OSX"
let tableInsert4 = "tableInsert4OSX"
#endif

class TestInsert: XCTestCase {

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

Expand All @@ -58,6 +61,14 @@ class TestInsert: XCTestCase {

let tableName = tableInsert3
}

class MyTable4 : Table {
let a = Column("a", String.self)
let b = Column("b", Int64.self, autoIncrement:true, primaryKey: true)

let tableName = tableInsert4
}

func testInsert() {
let t = MyTable()
let t2 = MyTable2()
Expand Down Expand Up @@ -238,4 +249,47 @@ class TestInsert: XCTestCase {
}
})
}

func testInsertNil() {
let t = MyTable4()

let pool = CommonUtils.sharedInstance.getConnectionPool()
performTest(asyncTasks: { expectation in
pool.getConnection { connection, error in
guard let connection = connection else {
XCTFail("Failed to get connection")
return
}
cleanUp(table: t.tableName, connection: connection) { result in
executeRawQuery("CREATE TABLE \"" + t.tableName + "\" (a TEXT, b SERIAL PRIMARY KEY)", connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "CREATE TABLE failed")
XCTAssertNil(result.asError, "Error in CREATE TABLE: \(result.asError!)")

let optionalString: String? = nil
let insertNil = Insert(into: t, valueTuples: [(t.a, optionalString as Any)])
executeQuery(query: insertNil, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "INSERT failed")
XCTAssertNil(result.asError, "Error in INSERT: \(result.asError!)")

let select = Select(from: t)
executeQuery(query: select, 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, 1, "SELECT returned wrong number of rows: \(String(describing: rows?.count)) instead of 1")
XCTAssertNil(rows?[0][0], "Expected value `nil` not found, returned: \(String(describing: rows?[0][0])) instead")

let drop = Raw(query: "DROP TABLE", table: t)
executeQuery(query: drop, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "DROP TABLE failed")
XCTAssertNil(result.asError, "Error in DELETE: \(result.asError!)")
expectation.fulfill()
}
}
}
}
}
}
})
}
}
48 changes: 47 additions & 1 deletion Tests/SwiftKueryPostgreSQLTests/TestSchema.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
Copyright IBM Corporation 2017, 2018
Copyright IBM Corporation 2017, 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,6 +35,7 @@ class TestSchema: XCTestCase {
("testPrimaryKeys", testPrimaryKeys),
("testTypes", testTypes),
("testAutoIncrement", testAutoIncrement),
("testCreateTableNilDefault", testCreateTableNilDefault),
]
}

Expand Down Expand Up @@ -451,4 +452,49 @@ class TestSchema: XCTestCase {
}
})
}

class MyNilDefaultTable: Table {
let a = Column("a", String.self, defaultValue: nil, nullDefaultValue: true)
let b = Column("b", Int64.self, autoIncrement: true, primaryKey: true)
let c = Column("c", Int64.self)

let tableName = "MyNilDefaultTable" + tableNameSuffix
}

func testCreateTableNilDefault() {
let t = MyNilDefaultTable()

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

pool.getConnection { connection, error in
guard let connection = connection else {
XCTFail("Failed to get connection")
return
}
cleanUp(table: t.tableName, connection: connection) { _ in
t.create(connection: connection) { result in
if let error = result.asError {
XCTFail("Error in CREATE TABLE: \(error)")
return
}

let insert = Insert(into: t, columns: [t.c], values: [5])
executeQuery(query: insert, connection: connection) { result, rows in
XCTAssertNil(result.asError, "Error in INSERT")

let select = Select(from: t)
executeQuery(query: select, connection: connection) { result, rows in
XCTAssertNil(result.asError, "Error on SELECT")
XCTAssertNotNil(rows, "Expected rows but none returned")
XCTAssertNil(rows?[0][0], "Non nil default value stored, expecting nil but returned \(String(describing: rows?[0][0]))")

expectation.fulfill()
}
}
}
}
}
})
}
}
49 changes: 48 additions & 1 deletion Tests/SwiftKueryPostgreSQLTests/TestUpdate.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
Copyright IBM Corporation 2016, 2017
Copyright IBM Corporation 2016, 2017, 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -30,6 +30,7 @@ class TestUpdate: XCTestCase {
static var allTests: [(String, (TestUpdate) -> () throws -> Void)] {
return [
("testUpdateAndDelete", testUpdateAndDelete),
("testUpdateNilValue", testUpdateNilValue),
]
}

Expand Down Expand Up @@ -141,4 +142,50 @@ class TestUpdate: XCTestCase {
}
})
}

func testUpdateNilValue() {
let t = MyTable()

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

pool.getConnection { connection, error in
guard let connection = connection else {
XCTFail("Failed to get connection")
return
}
cleanUp(table: t.tableName, connection: connection) { _ 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!)")

let insert = Insert(into: t, rows: [["apple", 10], ["apricot", 3], ["banana", 17], ["apple", 17], ["banana", -7], ["banana", 27]])
executeQuery(query: insert, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "INSERT failed")
XCTAssertNil(result.asError, "Error in INSERT: \(result.asError!)")

let nilString: String? = nil
let update = Update(t, set:[(t.a, nilString as Any)], where: t.a == "apple")
executeQuery(query: update, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "UPDATE failed")
XCTAssertNil(result.asError, "Error in UPDATE: \(result.asError!)")

let select = Select(from: t)
executeQuery(query: select, connection: connection) { result, rows in
XCTAssertEqual(result.success, true, "SELECT failed")
XCTAssertNil(result.asError, "Error in SELECT: \(result.asError!)")
XCTAssertNotNil(rows, "Expected rows but none returned")
for row in rows! {
XCTAssertNotEqual(row[0] as? String, "apple", "Row returned with \"apple\" instead of expected value \"nil\"")
}
expectation.fulfill()
}
}
}
}
}
}
})
}
}

0 comments on commit c56b52e

Please sign in to comment.