Convert Articles, ArticlesDatabase, and SyncDatabase to Swift Packages

This commit is contained in:
Maurice Parker
2020-07-30 04:54:21 -05:00
parent e3e5d69b9b
commit fbfdbb04c7
44 changed files with 91 additions and 1928 deletions

View File

@@ -1,25 +0,0 @@
//
// Constants.swift
// SyncDatabase
//
// Created by Maurice Parker on 5/14/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import Foundation
struct DatabaseTableName {
static let syncStatus = "syncStatus"
}
struct DatabaseKey {
// Sync Status
static let articleID = "articleID"
static let key = "key"
static let flag = "flag"
static let selected = "selected"
}

View File

@@ -1,92 +0,0 @@
//
// SyncDatabase.swift
// NetNewsWire
//
// Created by Maurice Parker on 5/14/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import Foundation
import RSCore
import RSDatabase
public typealias SyncStatusesResult = Result<Array<SyncStatus>, DatabaseError>
public typealias SyncStatusesCompletionBlock = (SyncStatusesResult) -> Void
public typealias SyncStatusArticleIDsResult = Result<Set<String>, DatabaseError>
public typealias SyncStatusArticleIDsCompletionBlock = (SyncStatusArticleIDsResult) -> Void
public struct SyncDatabase {
private let syncStatusTable: SyncStatusTable
private let queue: DatabaseQueue
public init(databaseFilePath: String) {
let queue = DatabaseQueue(databasePath: databaseFilePath)
try! queue.runCreateStatements(SyncDatabase.tableCreationStatements)
queue.vacuumIfNeeded(daysBetweenVacuums: 11)
self.queue = queue
self.syncStatusTable = SyncStatusTable(queue: queue)
}
// MARK: - API
public func insertStatuses(_ statuses: [SyncStatus]) throws {
try syncStatusTable.insertStatuses(statuses)
}
public func insertStatuses(_ statuses: [SyncStatus], completion: @escaping DatabaseCompletionBlock) {
syncStatusTable.insertStatuses(statuses, completion: completion)
}
public func selectForProcessing(limit: Int? = nil, completion: @escaping SyncStatusesCompletionBlock) {
return syncStatusTable.selectForProcessing(limit: limit, completion: completion)
}
public func selectPendingCount(completion: @escaping DatabaseIntCompletionBlock) {
syncStatusTable.selectPendingCount(completion)
}
public func selectPendingReadStatusArticleIDs(completion: @escaping SyncStatusArticleIDsCompletionBlock) {
syncStatusTable.selectPendingReadStatusArticleIDs(completion: completion)
}
public func selectPendingStarredStatusArticleIDs(completion: @escaping SyncStatusArticleIDsCompletionBlock) {
syncStatusTable.selectPendingStarredStatusArticleIDs(completion: completion)
}
public func resetAllSelectedForProcessing(completion: DatabaseCompletionBlock? = nil) {
syncStatusTable.resetAllSelectedForProcessing(completion: completion)
}
public func resetSelectedForProcessing(_ articleIDs: [String], completion: DatabaseCompletionBlock? = nil) {
syncStatusTable.resetSelectedForProcessing(articleIDs, completion: completion)
}
public func deleteSelectedForProcessing(_ articleIDs: [String], completion: DatabaseCompletionBlock? = nil) {
syncStatusTable.deleteSelectedForProcessing(articleIDs, completion: completion)
}
// MARK: - Suspend and Resume (for iOS)
/// Close the database and stop running database calls.
/// Any pending calls will complete first.
public func suspend() {
queue.suspend()
}
/// Open the database and allow for running database calls again.
public func resume() {
queue.resume()
}
}
// MARK: - Private
private extension SyncDatabase {
static let tableCreationStatements = """
CREATE TABLE if not EXISTS syncStatus (articleID TEXT NOT NULL, key TEXT NOT NULL, flag BOOL NOT NULL DEFAULT 0, selected BOOL NOT NULL DEFAULT 0, PRIMARY KEY (articleID, key));
"""
}

View File

@@ -1,298 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objects = {
/* Begin PBXBuildFile section */
51554C15228B6F0D0055115A /* SyncStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51554C12228B6F0D0055115A /* SyncStatus.swift */; };
51554C16228B6F0D0055115A /* SyncStatusTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51554C13228B6F0D0055115A /* SyncStatusTable.swift */; };
51554C17228B6F0D0055115A /* SyncDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51554C14228B6F0D0055115A /* SyncDatabase.swift */; };
51554C1E228B701F0055115A /* SyncDatabase_project.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 51554C19228B701F0055115A /* SyncDatabase_project.xcconfig */; };
51554C1F228B701F0055115A /* SyncDatabase_project_debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 51554C1A228B701F0055115A /* SyncDatabase_project_debug.xcconfig */; };
51554C21228B701F0055115A /* SyncDatabase_project_release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 51554C1C228B701F0055115A /* SyncDatabase_project_release.xcconfig */; };
51554C22228B701F0055115A /* SyncDatabase_target.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 51554C1D228B701F0055115A /* SyncDatabase_target.xcconfig */; };
51554C38228B7DAC0055115A /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51554C37228B7DAC0055115A /* Constants.swift */; };
51554C3A228B83380055115A /* Articles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C39228B83380055115A /* Articles.framework */; };
51B0DF1324D24EA6000AD99E /* RSDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = 51B0DF1224D24EA6000AD99E /* RSDatabase */; };
51B0DF1424D24EA6000AD99E /* RSDatabase in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 51B0DF1224D24EA6000AD99E /* RSDatabase */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
51B0DEC524D245A2000AD99E /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
51B0DF1424D24EA6000AD99E /* RSDatabase in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
51554BEB228B6E8F0055115A /* SyncDatabase.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SyncDatabase.framework; sourceTree = BUILT_PRODUCTS_DIR; };
51554BEF228B6E8F0055115A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
51554C12228B6F0D0055115A /* SyncStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncStatus.swift; sourceTree = "<group>"; };
51554C13228B6F0D0055115A /* SyncStatusTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncStatusTable.swift; sourceTree = "<group>"; };
51554C14228B6F0D0055115A /* SyncDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncDatabase.swift; sourceTree = "<group>"; };
51554C19228B701F0055115A /* SyncDatabase_project.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = SyncDatabase_project.xcconfig; sourceTree = "<group>"; };
51554C1A228B701F0055115A /* SyncDatabase_project_debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = SyncDatabase_project_debug.xcconfig; sourceTree = "<group>"; };
51554C1C228B701F0055115A /* SyncDatabase_project_release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = SyncDatabase_project_release.xcconfig; sourceTree = "<group>"; };
51554C1D228B701F0055115A /* SyncDatabase_target.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = SyncDatabase_target.xcconfig; sourceTree = "<group>"; };
51554C35228B72F40055115A /* RSDatabase.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSDatabase.framework; sourceTree = BUILT_PRODUCTS_DIR; };
51554C37228B7DAC0055115A /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
51554C39228B83380055115A /* Articles.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Articles.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
51554BE8228B6E8F0055115A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
51B0DF1324D24EA6000AD99E /* RSDatabase in Frameworks */,
51554C3A228B83380055115A /* Articles.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
51554BE1228B6E8F0055115A = {
isa = PBXGroup;
children = (
51554C37228B7DAC0055115A /* Constants.swift */,
51554C14228B6F0D0055115A /* SyncDatabase.swift */,
51554C12228B6F0D0055115A /* SyncStatus.swift */,
51554C13228B6F0D0055115A /* SyncStatusTable.swift */,
51554BEF228B6E8F0055115A /* Info.plist */,
51554BEC228B6E8F0055115A /* Products */,
51554C18228B6FBE0055115A /* xcconfig */,
51554C34228B72F40055115A /* Frameworks */,
);
sourceTree = "<group>";
};
51554BEC228B6E8F0055115A /* Products */ = {
isa = PBXGroup;
children = (
51554BEB228B6E8F0055115A /* SyncDatabase.framework */,
);
name = Products;
sourceTree = "<group>";
};
51554C18228B6FBE0055115A /* xcconfig */ = {
isa = PBXGroup;
children = (
51554C1A228B701F0055115A /* SyncDatabase_project_debug.xcconfig */,
51554C1C228B701F0055115A /* SyncDatabase_project_release.xcconfig */,
51554C19228B701F0055115A /* SyncDatabase_project.xcconfig */,
51554C1D228B701F0055115A /* SyncDatabase_target.xcconfig */,
);
path = xcconfig;
sourceTree = "<group>";
};
51554C34228B72F40055115A /* Frameworks */ = {
isa = PBXGroup;
children = (
51554C39228B83380055115A /* Articles.framework */,
51554C35228B72F40055115A /* RSDatabase.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
51554BE6228B6E8F0055115A /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
51554BEA228B6E8F0055115A /* SyncDatabase */ = {
isa = PBXNativeTarget;
buildConfigurationList = 51554BF3228B6E8F0055115A /* Build configuration list for PBXNativeTarget "SyncDatabase" */;
buildPhases = (
51554BE6228B6E8F0055115A /* Headers */,
51554BE7228B6E8F0055115A /* Sources */,
51554BE8228B6E8F0055115A /* Frameworks */,
51554BE9228B6E8F0055115A /* Resources */,
51C8F349234FB0C40048ED95 /* Run Script: Verfiy No Build Settings */,
51B0DEC524D245A2000AD99E /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = SyncDatabase;
packageProductDependencies = (
51B0DF1224D24EA6000AD99E /* RSDatabase */,
);
productName = SyncDatabase;
productReference = 51554BEB228B6E8F0055115A /* SyncDatabase.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
51554BE2228B6E8F0055115A /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = "Ranchero Software";
TargetAttributes = {
51554BEA228B6E8F0055115A = {
CreatedOnToolsVersion = 10.2.1;
};
};
};
buildConfigurationList = 51554BE5228B6E8F0055115A /* Build configuration list for PBXProject "SyncDatabase" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 51554BE1228B6E8F0055115A;
packageReferences = (
51B0DF1124D24EA6000AD99E /* XCRemoteSwiftPackageReference "RSDatabase" */,
);
productRefGroup = 51554BEC228B6E8F0055115A /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
51554BEA228B6E8F0055115A /* SyncDatabase */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
51554BE9228B6E8F0055115A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
51554C21228B701F0055115A /* SyncDatabase_project_release.xcconfig in Resources */,
51554C22228B701F0055115A /* SyncDatabase_target.xcconfig in Resources */,
51554C1F228B701F0055115A /* SyncDatabase_project_debug.xcconfig in Resources */,
51554C1E228B701F0055115A /* SyncDatabase_project.xcconfig in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
51C8F349234FB0C40048ED95 /* Run Script: Verfiy No Build Settings */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Run Script: Verfiy No Build Settings";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if [ \"$ENABLE_PREVIEWS\" = \"YES\" ]; then exit 0; fi\n\nxcrun -sdk macosx swiftc -target x86_64-macosx10.11 ../../buildscripts/VerifyNoBuildSettings.swift -o $CONFIGURATION_TEMP_DIR/VerifyNoBS\n$CONFIGURATION_TEMP_DIR/VerifyNoBS ${PROJECT_NAME}.xcodeproj/project.pbxproj\n\nif [ $? -ne 0 ]\nthen\n echo \"error: Build Setting were found in the project.pbxproj file. Most likely you didn't intend to change this file and should revert it.\"\n exit 1\nfi\n\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
51554BE7228B6E8F0055115A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
51554C15228B6F0D0055115A /* SyncStatus.swift in Sources */,
51554C16228B6F0D0055115A /* SyncStatusTable.swift in Sources */,
51554C17228B6F0D0055115A /* SyncDatabase.swift in Sources */,
51554C38228B7DAC0055115A /* Constants.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
51554BF1228B6E8F0055115A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 51554C1A228B701F0055115A /* SyncDatabase_project_debug.xcconfig */;
buildSettings = {
};
name = Debug;
};
51554BF2228B6E8F0055115A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 51554C1C228B701F0055115A /* SyncDatabase_project_release.xcconfig */;
buildSettings = {
};
name = Release;
};
51554BF4228B6E8F0055115A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 51554C1D228B701F0055115A /* SyncDatabase_target.xcconfig */;
buildSettings = {
};
name = Debug;
};
51554BF5228B6E8F0055115A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 51554C1D228B701F0055115A /* SyncDatabase_target.xcconfig */;
buildSettings = {
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
51554BE5228B6E8F0055115A /* Build configuration list for PBXProject "SyncDatabase" */ = {
isa = XCConfigurationList;
buildConfigurations = (
51554BF1228B6E8F0055115A /* Debug */,
51554BF2228B6E8F0055115A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
51554BF3228B6E8F0055115A /* Build configuration list for PBXNativeTarget "SyncDatabase" */ = {
isa = XCConfigurationList;
buildConfigurations = (
51554BF4228B6E8F0055115A /* Debug */,
51554BF5228B6E8F0055115A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
51B0DF1124D24EA6000AD99E /* XCRemoteSwiftPackageReference "RSDatabase" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Ranchero-Software/RSDatabase.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = "1.0.0-beta1";
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
51B0DF1224D24EA6000AD99E /* RSDatabase */ = {
isa = XCSwiftPackageProductDependency;
package = 51B0DF1124D24EA6000AD99E /* XCRemoteSwiftPackageReference "RSDatabase" */;
productName = RSDatabase;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 51554BE2228B6E8F0055115A /* Project object */;
}

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:SyncDatabase.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -1,48 +0,0 @@
//
// SyncStatus.swift
// NetNewsWire
//
// Created by Maurice Parker on 5/14/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import Foundation
import Articles
import RSDatabase
public struct SyncStatus: Hashable, Equatable {
public enum Key: String {
case read = "read"
case starred = "starred"
case deleted = "deleted"
case new = "new"
public init(_ articleStatusKey: ArticleStatus.Key) {
switch articleStatusKey {
case .read:
self = Self.read
case .starred:
self = Self.starred
}
}
}
public let articleID: String
public let key: SyncStatus.Key
public let flag: Bool
public let selected: Bool
public init(articleID: String, key: SyncStatus.Key, flag: Bool, selected: Bool = false) {
self.articleID = articleID
self.key = key
self.flag = flag
self.selected = selected
}
public func databaseDictionary() -> DatabaseDictionary {
return [DatabaseKey.articleID: articleID, DatabaseKey.key: key.rawValue, DatabaseKey.flag: flag, DatabaseKey.selected: selected]
}
}

View File

@@ -1,248 +0,0 @@
//
// SyncStatusTable.swift
// NetNewsWire
//
// Created by Maurice Parker on 5/14/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import Foundation
import RSCore
import Articles
import RSDatabase
import RSDatabaseObjC
struct SyncStatusTable: DatabaseTable {
let name = DatabaseTableName.syncStatus
private let queue: DatabaseQueue
init(queue: DatabaseQueue) {
self.queue = queue
}
func selectForProcessing(limit: Int?, completion: @escaping SyncStatusesCompletionBlock) {
queue.runInTransaction { databaseResult in
var statuses = Set<SyncStatus>()
var error: DatabaseError?
func makeDatabaseCall(_ database: FMDatabase) {
let updateSQL = "update syncStatus set selected = true"
database.executeUpdate(updateSQL, withArgumentsIn: nil)
var selectSQL = "select * from syncStatus where selected == true"
if let limit = limit {
selectSQL = "\(selectSQL) limit \(limit)"
}
if let resultSet = database.executeQuery(selectSQL, withArgumentsIn: nil) {
statuses = resultSet.mapToSet(self.statusWithRow)
}
}
switch databaseResult {
case .success(let database):
makeDatabaseCall(database)
case .failure(let databaseError):
error = databaseError
}
DispatchQueue.main.async {
if let error = error {
completion(.failure(error))
}
else {
completion(.success(Array(statuses)))
}
}
}
}
func selectPendingCount(_ completion: @escaping DatabaseIntCompletionBlock) {
queue.runInDatabase { databaseResult in
var count: Int = 0
var error: DatabaseError?
func makeDatabaseCall(_ database: FMDatabase) {
let sql = "select count(*) from syncStatus"
if let resultSet = database.executeQuery(sql, withArgumentsIn: nil) {
count = self.numberWithCountResultSet(resultSet)
}
}
switch databaseResult {
case .success(let database):
makeDatabaseCall(database)
case .failure(let databaseError):
error = databaseError
}
DispatchQueue.main.async {
if let error = error {
completion(.failure(error))
}
else {
completion(.success(count))
}
}
}
}
func selectPendingReadStatusArticleIDs(completion: @escaping SyncStatusArticleIDsCompletionBlock) {
selectPendingArticleIDsAsync(.read, completion)
}
func selectPendingStarredStatusArticleIDs(completion: @escaping SyncStatusArticleIDsCompletionBlock) {
selectPendingArticleIDsAsync(.starred, completion)
}
func resetAllSelectedForProcessing(completion: DatabaseCompletionBlock? = nil) {
queue.runInTransaction { databaseResult in
func makeDatabaseCall(_ database: FMDatabase) {
let updateSQL = "update syncStatus set selected = false"
database.executeUpdate(updateSQL, withArgumentsIn: nil)
}
switch databaseResult {
case .success(let database):
makeDatabaseCall(database)
callCompletion(completion, nil)
case .failure(let databaseError):
callCompletion(completion, databaseError)
}
}
}
func resetSelectedForProcessing(_ articleIDs: [String], completion: DatabaseCompletionBlock? = nil) {
queue.runInTransaction { databaseResult in
func makeDatabaseCall(_ database: FMDatabase) {
let parameters = articleIDs.map { $0 as AnyObject }
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(articleIDs.count))!
let updateSQL = "update syncStatus set selected = false where articleID in \(placeholders)"
database.executeUpdate(updateSQL, withArgumentsIn: parameters)
}
switch databaseResult {
case .success(let database):
makeDatabaseCall(database)
callCompletion(completion, nil)
case .failure(let databaseError):
callCompletion(completion, databaseError)
}
}
}
func deleteSelectedForProcessing(_ articleIDs: [String], completion: DatabaseCompletionBlock? = nil) {
queue.runInTransaction { databaseResult in
func makeDatabaseCall(_ database: FMDatabase) {
let parameters = articleIDs.map { $0 as AnyObject }
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(articleIDs.count))!
let deleteSQL = "delete from syncStatus where selected = true and articleID in \(placeholders)"
database.executeUpdate(deleteSQL, withArgumentsIn: parameters)
}
switch databaseResult {
case .success(let database):
makeDatabaseCall(database)
callCompletion(completion, nil)
case .failure(let databaseError):
callCompletion(completion, databaseError)
}
}
}
func insertStatuses(_ statuses: [SyncStatus]) throws {
var error: DatabaseError?
queue.runInTransactionSync { databaseResult in
switch databaseResult {
case .success(let database):
let statusArray = statuses.map { $0.databaseDictionary() }
self.insertRows(statusArray, insertType: .orReplace, in: database)
case .failure(let databaseError):
error = databaseError
}
}
if let error = error {
throw error
}
}
func insertStatuses(_ statuses: [SyncStatus], completion: @escaping DatabaseCompletionBlock) {
queue.runInTransaction { databaseResult in
func makeDatabaseCall(_ database: FMDatabase) {
let statusArray = statuses.map { $0.databaseDictionary() }
self.insertRows(statusArray, insertType: .orReplace, in: database)
}
switch databaseResult {
case .success(let database):
makeDatabaseCall(database)
completion(nil)
case .failure(let databaseError):
completion(databaseError)
}
}
}
}
private extension SyncStatusTable {
func statusWithRow(_ row: FMResultSet) -> SyncStatus? {
guard let articleID = row.string(forColumn: DatabaseKey.articleID),
let rawKey = row.string(forColumn: DatabaseKey.key),
let key = SyncStatus.Key(rawValue: rawKey) else {
return nil
}
let flag = row.bool(forColumn: DatabaseKey.flag)
let selected = row.bool(forColumn: DatabaseKey.selected)
return SyncStatus(articleID: articleID, key: key, flag: flag, selected: selected)
}
func selectPendingArticleIDsAsync(_ statusKey: ArticleStatus.Key, _ completion: @escaping SyncStatusArticleIDsCompletionBlock) {
queue.runInDatabase { databaseResult in
func makeDatabaseCall(_ database: FMDatabase) {
let sql = "select articleID from syncStatus where selected == false and key = \"\(statusKey.rawValue)\";"
guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else {
DispatchQueue.main.async {
completion(.success(Set<String>()))
}
return
}
let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) }
DispatchQueue.main.async {
completion(.success(articleIDs))
}
}
switch databaseResult {
case .success(let database):
makeDatabaseCall(database)
case .failure(let databaseError):
DispatchQueue.main.async {
completion(.failure(databaseError))
}
}
}
}
}
private func callCompletion(_ completion: DatabaseCompletionBlock?, _ databaseError: DatabaseError?) {
guard let completion = completion else {
return
}
DispatchQueue.main.async {
completion(databaseError)
}
}