147 lines
4.5 KiB
Swift
147 lines
4.5 KiB
Swift
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
|
|
}
|
|
|
|
}
|