Skip to content

Commit 46ebda7

Browse files
committed
Update SQLiteAdapter.swift
* Read methods now return nil if no rows have been read * Insert, update, and delete methods now return the number of changes made * Updated addIndex method * Optimized some other code
1 parent f0a97b9 commit 46ebda7

1 file changed

Lines changed: 113 additions & 72 deletions

File tree

Sources/SQLiteAdapter/SQLiteAdapter.swift

Lines changed: 113 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,20 @@ public protocol SQLiteType {
5858
func dropIndex(in table: SQLTable, forColumn columnName: String) throws
5959
func beginTransaction() throws
6060
func endTransaction() throws
61-
func insertRow(sql: String, params: [Any]?) throws -> Int
62-
func updateRow(sql: String, params: [Any]?) throws
63-
func deleteRow(sql: String, params: [Any]?) throws
64-
func deleteByID(in table: SQLTable, id: Int) throws
65-
func deleteAllRows(in table: SQLTable, vacuum: Bool, resetAutoincrement: Bool) throws
61+
func insertRow(sql: String, params: [Any]?) throws -> (Int, Int)
62+
func updateRow(sql: String, params: [Any]?) throws -> Int
63+
func deleteRow(sql: String, params: [Any]?) throws -> Int
64+
func deleteByID(in table: SQLTable, id: Int) throws -> Int
65+
func deleteAllRows(in table: SQLTable, vacuum: Bool, resetAutoincrement: Bool) throws -> Int
6666
func getRowCount(in table: SQLTable) throws -> Int
6767
func getRowCountWithCondition(sql: String, params: [Any]?) throws -> Int
68-
func getRow(from table: SQLTable, sql: String, params: [Any]?) throws -> [SQLValues]
69-
func getAllRows(from table: SQLTable) throws -> [SQLValues]
70-
func getByID(from table: SQLTable, id: Int) throws -> SQLValues
71-
func getFirstRow(from table: SQLTable) throws -> SQLValues
72-
func getLastRow(from table: SQLTable) throws -> SQLValues
68+
func getRow(from table: SQLTable, sql: String, params: [Any]?) throws -> [SQLValues]?
69+
func getAllRows(from table: SQLTable) throws -> [SQLValues]?
70+
func getByID(from table: SQLTable, id: Int) throws -> SQLValues?
71+
func getFirstRow(from table: SQLTable) throws -> SQLValues?
72+
func getLastRow(from table: SQLTable) throws -> SQLValues?
7373
func vacuum() throws
74-
func query(sql: String, params: [Any]?) throws
74+
func query(sql: String, params: [Any]?) throws -> Int
7575
}
7676

7777
open class SQLite: SQLiteType {
@@ -95,23 +95,23 @@ open class SQLite: SQLiteType {
9595
return id
9696
}
9797

98-
/// Returns number of rows changed by last INSERT, UPDATE or DELETE statement
98+
/// - Returns: the number of rows changed by the most recently completed INSERT, DELETE or UPDATE statement
9999
public var changes: Int {
100100
var changes = 0
101101
queue.sync {
102102
changes = Int(sqlite3_changes(dbPointer))
103103
}
104-
log("number of changes: \(changes)")
104+
log("changes: \(changes)")
105105
return changes
106106
}
107107

108-
/// Returns number of rows changed by INSERT, UPDATE or DELETE statements since the DB was opened
108+
/// - Returns: the number of rows changed by INSERT, DELETE or UPDATE statements since the current DB was opened
109109
public var totalChanges: Int {
110110
var totalChanges = 0
111111
queue.sync {
112112
totalChanges = Int(sqlite3_total_changes(dbPointer))
113113
}
114-
log("number of total changes: \(totalChanges)")
114+
log("total changes: \(totalChanges)")
115115
return totalChanges
116116
}
117117

@@ -156,7 +156,7 @@ open class SQLite: SQLiteType {
156156
do {
157157
try fileManager.removeItem(atPath: path)
158158
} catch {
159-
throw SQLiteError.Other("SQLite file has not been deleted")
159+
throw SQLiteError.OpenDB("SQLite file has not been deleted")
160160
}
161161
}
162162

@@ -223,7 +223,8 @@ open class SQLite: SQLiteType {
223223
}
224224
}
225225

226-
private func operation(sql: String, params: [Any]? = nil) throws {
226+
@discardableResult
227+
private func operation(sql: String, params: [Any]? = nil) throws -> Int {
227228
try queue.sync {
228229
let sqlStatement = try prepareStatement(sql: sql)
229230

@@ -236,6 +237,8 @@ open class SQLite: SQLiteType {
236237
guard sqlite3_step(sqlStatement) == SQLITE_DONE else {
237238
throw SQLiteError.Step(getErrorMessage(dbPointer: dbPointer))
238239
}
240+
241+
return Int(sqlite3_changes(dbPointer))
239242
}
240243
}
241244

@@ -253,12 +256,10 @@ open class SQLite: SQLiteType {
253256
}
254257

255258
public func checkIfTableExists(_ table: SQLTable) throws -> Bool {
256-
if let count = try? getRowCountWithCondition(sql: "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='\(table.name)';") {
257-
let result = count == 1 ? true : false
258-
log("successfully checked if table \(table.name) exists: \(result)")
259-
return result
260-
}
261-
throw SQLiteError.Other(getErrorMessage(dbPointer: dbPointer))
259+
let count = try getRowCountWithCondition(sql: "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='\(table.name)';")
260+
let result = count == 1 ? true : false
261+
log("successfully checked if table \(table.name) exists: \(result)")
262+
return result
262263
}
263264

264265
public func dropTable(_ table: SQLTable, vacuum: Bool = true) throws {
@@ -276,9 +277,9 @@ open class SQLite: SQLiteType {
276277

277278
var sql = ""
278279
if !unique {
279-
sql = "CREATE INDEX \"\(indexName)\" ON \"\(table.name)\" (\"\(columnName)\""
280+
sql = "CREATE INDEX IF NOT EXISTS \"\(indexName)\" ON \"\(table.name)\" (\"\(columnName)\""
280281
} else {
281-
sql = "CREATE UNIQUE INDEX \"\(indexName))\" ON \"\(table.name)\" (\"\(columnName)\""
282+
sql = "CREATE UNIQUE INDEX IF NOT EXISTS \"\(indexName))\" ON \"\(table.name)\" (\"\(columnName)\""
282283
}
283284

284285
switch order {
@@ -295,12 +296,10 @@ open class SQLite: SQLiteType {
295296
}
296297

297298
public func checkIfIndexExists(in table: SQLTable, indexName: String) throws -> Bool {
298-
if let count = try? getRowCountWithCondition(sql: "SELECT count(*) FROM sqlite_master WHERE type='index' AND tbl_name='\(table.name)' AND name='\(indexName)';") {
299-
let result = count == 1 ? true : false
300-
log("successfully checked if index \(indexName) exists: \(result)")
301-
return result
302-
}
303-
throw SQLiteError.Other(getErrorMessage(dbPointer: dbPointer))
299+
let count = try getRowCountWithCondition(sql: "SELECT count(*) FROM sqlite_master WHERE type='index' AND tbl_name='\(table.name)' AND name='\(indexName)';")
300+
let result = count == 1 ? true : false
301+
log("successfully checked if index \(indexName) exists: \(result)")
302+
return result
304303
}
305304

306305
public func dropIndex(in table: SQLTable, forColumn columnName: String) throws {
@@ -323,50 +322,83 @@ open class SQLite: SQLiteType {
323322
}
324323

325324
/// Can be used to insert one or several rows depending on the SQL statement
326-
/// - Returns: The id for the last inserted row
327-
public func insertRow(sql: String, params: [Any]? = nil) throws -> Int {
325+
/// - Returns: (the number of inserted rows, id for the last inserted row)
326+
@discardableResult
327+
public func insertRow(sql: String, params: [Any]? = nil) throws -> (Int, Int) {
328328
guard sql.uppercased().trimmingCharacters(in: .whitespaces).hasPrefix("INSERT ") else {
329329
throw SQLiteError.Statement("Invalid SQL statement")
330330
}
331-
try operation(sql: sql, params: params)
332-
log("successfully inserted row(s), sql: \(sql)")
333-
return self.lastInsertID
331+
let changes = try operation(sql: sql, params: params)
332+
if changes > 0 {
333+
log("successfully inserted row(s), sql: \(sql)")
334+
} else {
335+
log("no rows were inserted, sql: \(sql)")
336+
}
337+
return (changes, lastInsertID)
334338
}
335339

336340
/// Can be used to update one or several rows depending on the SQL statement
337-
public func updateRow(sql: String, params: [Any]? = nil) throws {
341+
/// - Returns: the number of updated rows
342+
@discardableResult
343+
public func updateRow(sql: String, params: [Any]? = nil) throws -> Int {
338344
guard sql.uppercased().trimmingCharacters(in: .whitespaces).hasPrefix("UPDATE ") else {
339345
throw SQLiteError.Statement("Invalid SQL statement")
340346
}
341-
try operation(sql: sql, params: params)
342-
log("successfully updated row(s), sql: \(sql)")
347+
let changes = try operation(sql: sql, params: params)
348+
if changes > 0 {
349+
log("successfully updated row(s), sql: \(sql)")
350+
} else {
351+
log("no rows were updated, sql: \(sql)")
352+
}
353+
return changes
343354
}
344355

345356
/// Can be used to delete one or several rows depending on the SQL statement
346-
public func deleteRow(sql: String, params: [Any]? = nil) throws {
357+
/// - Returns: the number of deleted rows
358+
@discardableResult
359+
public func deleteRow(sql: String, params: [Any]? = nil) throws -> Int {
347360
guard sql.uppercased().trimmingCharacters(in: .whitespaces).hasPrefix("DELETE ") else {
348361
throw SQLiteError.Statement("Invalid SQL statement")
349362
}
350-
try operation(sql: sql, params: params)
351-
log("successfully deleted row(s), sql: \(sql)")
363+
let changes = try operation(sql: sql, params: params)
364+
if changes > 0 {
365+
log("successfully deleted row(s), sql: \(sql)")
366+
} else {
367+
log("no rows were deleted, sql: \(sql)")
368+
}
369+
return changes
352370
}
353371

354-
public func deleteByID(in table: SQLTable, id: Int) throws {
372+
/// - Returns: 1 if the row with the specified id was deleted, otherwise returns 0
373+
@discardableResult
374+
public func deleteByID(in table: SQLTable, id: Int) throws -> Int {
355375
let sql = "DELETE FROM \(table.name) WHERE \(table.primaryKey) = ?;"
356-
try operation(sql: sql, params: [id])
357-
log("successfully deleted a row by id \(id) in \(table.name)")
376+
let changes = try operation(sql: sql, params: [id])
377+
if changes == 1 {
378+
log("successfully deleted the row with id \(id) in \(table.name)")
379+
} else {
380+
log("row with id \(id) was not deleted in \(table.name)")
381+
}
382+
return changes
358383
}
359384

360-
public func deleteAllRows(in table: SQLTable, vacuum: Bool = true, resetAutoincrement: Bool = true) throws {
385+
/// - Returns: the number of deleted rows
386+
@discardableResult
387+
public func deleteAllRows(in table: SQLTable, vacuum: Bool = true, resetAutoincrement: Bool = true) throws -> Int {
361388
let sql = "DELETE FROM \(table.name);"
362-
try operation(sql: sql)
363-
log("successfully deleted all rows in \(table.name)")
389+
let changes = try operation(sql: sql)
390+
if changes > 0 {
391+
log("successfully deleted all rows in \(table.name)")
392+
} else {
393+
log("no rows were deleted in \(table.name)")
394+
}
364395
if vacuum {
365396
try self.vacuum()
366397
}
367398
if resetAutoincrement {
368399
try self.resetAutoincrement(in: table)
369400
}
401+
return changes
370402
}
371403

372404
public func getRowCount(in table: SQLTable) throws -> Int {
@@ -409,7 +441,8 @@ open class SQLite: SQLiteType {
409441
}
410442

411443
/// Can be used to read one or several rows depending on the SQL statement
412-
public func getRow(from table: SQLTable, sql: String, params: [Any]? = nil) throws -> [SQLValues] {
444+
/// - Returns: [SQLValues] if one or more rows were selected, otherwise returns nil
445+
public func getRow(from table: SQLTable, sql: String, params: [Any]? = nil) throws -> [SQLValues]? {
413446
guard sql.uppercased().trimmingCharacters(in: .whitespaces).hasPrefix("SELECT ") else {
414447
throw SQLiteError.Statement("Invalid SQL statement")
415448
}
@@ -488,8 +521,13 @@ open class SQLite: SQLiteType {
488521
}
489522
}
490523

491-
log("successfully read row(s), count: \(allRows.count), sql: \(sql)")
492-
return allRows
524+
if allRows.count > 0 {
525+
log("successfully read row(s), count: \(allRows.count), sql: \(sql)")
526+
return allRows
527+
} else {
528+
log("no rows selected, sql: \(sql)")
529+
return nil
530+
}
493531
}
494532

495533
/// Checks the structure of the result table and synchronizes it in SQLTableColums
@@ -516,44 +554,44 @@ open class SQLite: SQLiteType {
516554
return resultColumns
517555
}
518556

519-
public func getAllRows(from table: SQLTable) throws -> [SQLValues] {
557+
/// - Returns: [SQLValues] if one or more rows were selected, otherwise returns nil
558+
public func getAllRows(from table: SQLTable) throws -> [SQLValues]? {
520559
let sql = "SELECT * FROM \(table.name);"
521-
let result = try getRow(from: table, sql: sql)
522-
log("successfully read all rows in \(table.name), count: \(result.count)")
523-
return result
560+
if let result = try getRow(from: table, sql: sql) {
561+
log("successfully read all rows in \(table.name), count: \(result.count)")
562+
return result
563+
}
564+
return nil
524565
}
525566

526-
public func getByID(from table: SQLTable, id: Int) throws -> SQLValues {
567+
/// - Returns: SQLValues if a row was selected, otherwise returns nil
568+
public func getByID(from table: SQLTable, id: Int) throws -> SQLValues? {
527569
let sql = "SELECT * FROM \(table.name) WHERE \(table.primaryKey) = ? LIMIT 1;"
528-
let result = try getRow(from: table, sql: sql, params: [id])
529-
if result.count == 1 {
570+
if let result = try getRow(from: table, sql: sql, params: [id]) {
530571
log("successfully read a row by id \(id) in \(table.name)")
531572
return result[0]
532-
} else {
533-
throw SQLiteError.Other(getErrorMessage(dbPointer: dbPointer))
534573
}
574+
return nil
535575
}
536576

537-
public func getFirstRow(from table: SQLTable) throws -> SQLValues {
577+
/// - Returns: SQLValues if a row was selected, otherwise returns nil
578+
public func getFirstRow(from table: SQLTable) throws -> SQLValues? {
538579
let sql = "SELECT * FROM \(table.name) WHERE \(table.primaryKey) = (SELECT MIN(\(table.primaryKey)) FROM \(table.name));"
539-
let result = try getRow(from: table, sql: sql)
540-
if result.count == 1 {
580+
if let result = try getRow(from: table, sql: sql) {
541581
log("successfully read the first row in \(table.name)")
542582
return result[0]
543-
} else {
544-
throw SQLiteError.Other(getErrorMessage(dbPointer: dbPointer))
545583
}
584+
return nil
546585
}
547586

548-
public func getLastRow(from table: SQLTable) throws -> SQLValues {
587+
/// - Returns: SQLValues if a row was selected, otherwise returns nil
588+
public func getLastRow(from table: SQLTable) throws -> SQLValues? {
549589
let sql = "SELECT * FROM \(table.name) WHERE \(table.primaryKey) = (SELECT MAX(\(table.primaryKey)) FROM \(table.name));"
550-
let result = try getRow(from: table, sql: sql)
551-
if result.count == 1 {
590+
if let result = try getRow(from: table, sql: sql) {
552591
log("successfully read the last row in \(table.name)")
553592
return result[0]
554-
} else {
555-
throw SQLiteError.Other(getErrorMessage(dbPointer: dbPointer))
556593
}
594+
return nil
557595
}
558596

559597
/// Repacks the DB to take advantage of deleted data
@@ -564,8 +602,11 @@ open class SQLite: SQLiteType {
564602
}
565603

566604
/// Any other query except reading
567-
public func query(sql: String, params: [Any]? = nil) throws {
568-
try operation(sql: sql, params: params)
605+
/// - Returns: the number of rows changed
606+
@discardableResult
607+
public func query(sql: String, params: [Any]? = nil) throws -> Int {
608+
let changes = try operation(sql: sql, params: params)
569609
log("successful query, sql: \(sql)")
610+
return changes
570611
}
571612
}

0 commit comments

Comments
 (0)