import Combine import GRDB import GRDBQuery var idColumn = Column("id") struct RibbonRequest: Queryable { enum UndoDir { case prev case next } /// The ordering used by the player request. // var ordering: Ordering var id: Int64! var dir: UndoDir? var groupId: Int? // MARK: - Queryable Implementation static var defaultValue: [Ribbon] { [] } func publisher(in appDatabase: AppDatabase) -> AnyPublisher<[Ribbon], Error> { // Build the publisher from the general-purpose read-only access // granted by `appDatabase.reader`. // Some apps will prefer to call a dedicated method of `appDatabase`. ValueObservation .tracking(fetchValue(_:)) .publisher( in: appDatabase.reader, // The `.immediate` scheduling feeds the view right on // subscription, and avoids an undesired animation when the // application starts. scheduling: .immediate) .eraseToAnyPublisher() } // This method is not required by Queryable, but it makes it easier func fetchValue(_ db: Database) throws -> [Ribbon] { var ret: [Ribbon] var sql: String // this has to be a global variable let totalLevels = 3 do { if dir != nil && groupId != nil { sql = """ SELECT * FROM Ribbon \ WHERE groupId = ? """ ret = try Ribbon.fetchAll(db, sql: sql, arguments: [groupId]) if ret.count == 0 { print("error no ribbons found") return [] } print("back all ribbon test: \(ret)") let currentLevel = ret[0].currentLevel let minLevel = ret[0].minLevel let maxLevel = ret[0].maxLevel var newCurrentLevel = (currentLevel - 1) %% totalLevels // probably need more error checking to check // if current level gets into an error state // between minLevel and maxLevel somehow but there // are probably a bunch of edge cases casue of the // mod stuff if dir == .prev { // no back undo steps left if currentLevel == minLevel { return [] } } else if dir == .prev { // no forward redo steps left if currentLevel == maxLevel { return [] } newCurrentLevel = (currentLevel + 1) %% totalLevels } print("back newcurrentlevel \(newCurrentLevel)") sql = """ SELECT * FROM Ribbon \ WHERE groupId = ? AND undoLevel = ? LIMIT 1 """ ret = try Ribbon.fetchAll(db, sql: sql, arguments: [groupId, newCurrentLevel]) print("back ribbon test: \(ret)") return ret } else { let sql = """ select distinct r1.* from Ribbon r1 join Ribbon r2 ON \ r1.undoLevel = r2.currentLevel AND r1.id = r2.id ORDER BY pos ASC """ var ret = try Ribbon.fetchAll(db, sql: sql) print("xxxxx fetching ribbons") print(ret) return ret } } catch { print(error.localizedDescription) print(error) print("Error") return [] } // if id == nil { // return try Ribbon.order(Column("pos")).fetchAll(db) // } else { // return try Ribbon.filter(idColumn == id).fetchAll(db) // } // { // if book == "" { // return try Ribbon.filter(bookColumn == Ribbon.randomBook()).fetchAll(db) // } else { // return try Ribbon.filter(bookColumn == book).fetchAll(db) // } // switch ordering { // case .byScore: // return try Ribbon.all().fetchAll(db) // case .byName: // // return try Ribbon.all().orderedByName().fetchAll(db) // return try Ribbon.all().fetchAll(db) // } } } infix operator %% extension Int { static func %% (_ left: Int, _ right: Int) -> Int { let mod = left % right return mod >= 0 ? mod : mod + right } }