// // FuelEntryControllerV2_2.swift // Fueling // // Created by Michiel Carman on 10/26/26. // // // FuelEntryControllerV2_1.swift // Fueling // // Created by Michiel Carman on 9/15/26. // import Vapor import FluentKit import FluentSQL struct FuelEntryV2ControllerV2_2: RouteCollection { func boot(routes: RoutesBuilder) throws { let fuelEntries = routes.grouped("fuel_entries") let tokenAuthMiddleware = Token.authenticator() let guardMiddleware = User.guardMiddleware() let tokenAuthGroup = fuelEntries.grouped(tokenAuthMiddleware, guardMiddleware) tokenAuthGroup.get(use: filterLoadDate) tokenAuthGroup.get("main", use: filterLoadDate) tokenAuthGroup.get("timestamp", use: filterTimeStamp) tokenAuthGroup.get("images", use: filterImages) tokenAuthGroup.get("test", use: filtered) tokenAuthGroup.get("rpm", use: rpm) tokenAuthGroup.get("maxim", use: filtered) tokenAuthGroup.post(use: create) tokenAuthGroup.put( use: softdelete) tokenAuthGroup.group(":fuelEntryID") { fuelEntry in fuelEntry.delete(use: delete) } } @Sendable func index(req: Request) async throws -> Response { return try await FuelEntry.query(on: req.db).all().map{ try FuelEntry.V2_1_Output.init(from: $0) }.encodeResponse(for: req) } struct filteredreturn: Content{ var fuelentries: [FuelEntry] var pages: Int } struct dload: Content{ var id: UUID } @Sendable func softdelete(req: Request) async throws -> Response { let ids = try req.content.decode([dload].self) var msg: [String] = [] for id in ids { guard let fe = try await FuelEntry.find(id.id, on: req.db) else { msg.append("create error message for item") continue } fe.downloaded = true try await fe.save(on: req.db) } let response = Response(status: .ok, body: "good") return response } fileprivate func queryParamExists(_ req: Request, _ param: String) async throws -> Bool { let x = try req.query.get(Bool.self, at: param) ? true : false print ("x: \(x)") return x } fileprivate func parseDate2(_ dateString: String, _ start: Bool = true) throws -> Date? { let currentDate = Calendar.current.startOfDay(for: Date()) if(dateString.count == 0 && start){ if(start) { return Calendar.current.date(byAdding: .day, value: -2, to: currentDate) } else { return currentDate } } else { let parts = dateString.split(separator: "-") if(parts.count != 3) { return nil } let year = Int(parts[0]) ?? nil if(year == nil) { return nil } let month = Int(parts[1]) ?? nil if(month == nil) { return nil } let day = Int(parts[2]) ?? nil if( day == nil ) { return nil } var dateComponents = DateComponents() dateComponents.year = year dateComponents.month = month dateComponents.day = day if(start) { dateComponents.hour = 0 dateComponents.minute = 0 dateComponents.second = 0 } else { dateComponents.hour = 23 dateComponents.minute = 59 dateComponents.second = 59 } let calendar = Calendar(identifier: .gregorian) return calendar.date(from: dateComponents) } } fileprivate func parseDate(_ dateString: String, _ start: Bool = true) throws -> Date? { if(dateString.count == 0){ return nil } else { let parts = dateString.split(separator: "-") if(parts.count != 3) { throw Abort(.custom(code: 400,reasonPhrase: "Value at path '\(start ? "startdate" : "enddate")' was not of format 'yyyy-MM-dd'. Data found at '\(start ? "startdate" : "enddate")' was not properly formatted.")) } let year = Int(parts[0]) ?? nil if(year == nil) { throw Abort(.custom(code: 400,reasonPhrase: "Value at path '\(start ? "startdate" : "enddate")' was not of format 'yyyy-MM-dd'. Data found at '\(start ? "startdate" : "enddate")' was not properly formatted. Year component must be in the format yyyy and must be an integer")) } let month = Int(parts[1]) ?? nil if(month == nil) { throw Abort(.custom(code: 400,reasonPhrase: "Value at path '\(start ? "startdate" : "enddate")' was not of format 'yyyy-MM-dd'. Data found at '\(start ? "startdate" : "enddate")' was not properly formatted. Month component must be in the format MM and must be an integer")) } let day = Int(parts[2]) ?? nil if( day == nil ) { throw Abort(.custom(code: 400,reasonPhrase: "Value at path '\(start ? "startdate" : "enddate")' was not of format 'yyyy-MM-dd'. Data found at '\(start ? "startdate" : "enddate")' was not properly formatted. Day component must be in the format dd and must be an integer")) } var dateComponents = DateComponents() dateComponents.year = year dateComponents.month = month dateComponents.day = day if(start) { dateComponents.hour = 0 dateComponents.minute = 0 dateComponents.second = 0 } else { dateComponents.hour = 23 dateComponents.minute = 59 dateComponents.second = 59 } let calendar = Calendar(identifier: .gregorian) return calendar.date(from: dateComponents) } } fileprivate func generateSQLNoImage(_ startdate: Date? = nil, _ enddate: Date? = nil) -> SQLQueryString { if(startdate == nil) { return SQLQueryString("select count(*) as total from \"fuel_entries\";") } if(enddate != nil) { return SQLQueryString("select count(*) as total from \"fuel_entries\" where \"loadDate\" >= \(bind: startdate) and \"loadDate\" <= \(bind: enddate) ;") } else { return SQLQueryString("select count(*) as total from \"fuel_entries\" where \"loadDate\" >= \(bind: startdate);") } } fileprivate func generateSQLImage(_ startdate: Date? = nil, _ enddate: Date? = nil) -> SQLQueryString { var sql: String = "" if(startdate == nil) { return SQLQueryString("select count(*) as total from \"fuel_entries\" where \"image\" is not null;") } if(enddate != nil) { sql = "select count(*) as total from \"fuel_entries\" where \"loadDate\" >= \(String(describing: startdate)) and \"loadDate\" <= \(String(describing: enddate)) and \"image\" is not null;" return SQLQueryString("select count(*) as total from \"fuel_entries\" where \"loadDate\" >= \(bind: startdate) and \"loadDate\" <= \(bind: enddate) and \"image\" is not null;") } else { sql = "select count(*) as total from \"fuel_entries\" where \"image\" is not null and \"loadDate\" >= '\(startdate ?? Date())';" return SQLQueryString(sql) } } struct CountRecords: Content { let total: Int } fileprivate func getCount(_ req: Request, _ sql: SQLQueryString) async throws -> Int { print(sql) if let db = req.db as? SQLDatabase { let answer = try await db .raw(sql) .first(decoding: CountRecords.self) return answer?.total ?? 0 } else { return 0 } } fileprivate func getPaging(_ page: Int, _ per: Int, _ records: Int) async throws -> [String: Any] { var vals: [String: Any] = [:] vals["page"] = page vals["per"] = per vals["records"] = records let lastpage = Int(ceil(Double(records) / Double(per))) vals["lastpage"] = (page == lastpage) ? true : false vals["offset"] = ( page * per) - per return vals } fileprivate func getParams(_ req: Request) async throws -> [qparam] { let urlComponents = URLComponents(string: req.url.description)! var params: [qparam] = [] for queryItem in urlComponents.queryItems ?? [] { params.append(qparam(name: queryItem.name, value: queryItem.value ?? "")) } return params } fileprivate func getMaximError(_ req: Request, _ message: String) async throws -> returnObjV2_1 { let rt = req.route!.description.replacingOccurrences(of: "GET ", with: "").replacingOccurrences(of: "PUT ", with: "").replacingOccurrences(of: "POST ", with: "").replacingOccurrences(of: "DELETE ", with: "") let method = req.method.rawValue let baseurl = "https://fueling.prelub.com" let data : [FuelEntry.V2_1_Output] = [] let meta = Meta(page: 0, per: 0, total: 0, lastpage: true, error: true, message: message, method: method, baseurl: baseurl, route: rt, querystring: "" ) return returnObjV2_1(data: data, meta: meta) } @Sendable func filterLoadDate(req: Request) async throws -> Response { let rt = req.route!.description.replacingOccurrences(of: "GET ", with: "").replacingOccurrences(of: "PUT ", with: "").replacingOccurrences(of: "POST ", with: "").replacingOccurrences(of: "DELETE ", with: "") let method = req.method.rawValue let baseurl = "https://fueling.prelub.com" let qstring = req.query let components: Dictionary = try req.query.decode(Dictionary.self) var startdate : Date? var qs: [String] = [] for component in components { qs.append( "\(component.key)=\(component.value ?? "nil")") } if(try qstring.get(String?.self, at: "startdate") != nil) { startdate = try parseDate2(qstring.get(String?.self, at: "startdate") ?? "") if(startdate == nil) { return try await(getMaximError(req, "startdate is invalid format. YYYY-MM-DD")) .encodeResponse(for: req) } } else { //throw error return try await getMaximError(req, "startdate is required").encodeResponse(for: req) } var enddate : Date?//= try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) if(try qstring.get(String?.self, at: "enddate") != nil) { enddate = try parseDate2(qstring.get(String?.self, at: "enddate") ?? "", false) if(enddate == nil) { return try await getMaximError(req, "enddate is invalid format. YYYY-MM-DD").encodeResponse(for: req) } } let emptyData: Data? = Data() let page = try qstring.get(Int?.self, at: "page") ?? 1 let per = try qstring.get(Int?.self, at: "per") ?? 10 let qsStr = qs.joined(separator: "&") let records = try await getCount(req, generateSQLNoImage(startdate ?? nil, enddate ?? nil) ) let paging = try await getPaging(page, per, records) let meta = Meta(page: page, per: per, total: records, lastpage: (paging["lastpage"] != nil) ? paging["lastpage"] as! Bool : false, error: false, message: "", method: method, baseurl: baseurl, route: rt, querystring: "?\(qsStr)") let query = try await FuelEntry.query(on: req.db) .field(\.$id) .field(\.$timestamp) .field(\.$userID) .field(\.$product) .field(\.$make) .field(\.$model) .field(\.$serialNumber) .field(\.$tankID) .field(\.$fuelAmount) .field(\.$fuelType) .field(\.$isOverride) .field(\.$latitude) .field(\.$longitude) .field(\.$downloaded) .field(\.$loaddate) .field(\.$tabletserial) .group(.and) { grp in grp.filter(\.$loaddate >= startdate) if( enddate != nil) { grp.filter(\.$loaddate <= enddate!) } } .sort(\.$loaddate, .ascending) .range(lower: (paging["offset"] as! Int), upper: (paging["offset"] as! Int) + (paging["per"] as! Int)) .all().map{ try FuelEntry.V2_1_Output.init(from: $0) } let response = returnObjV2_1(data: query, meta: meta) return try await response.encodeResponse(for: req) } @Sendable func filterImages(req: Request) async throws -> Response { let rt = req.route!.description.replacingOccurrences(of: "GET ", with: "").replacingOccurrences(of: "PUT ", with: "").replacingOccurrences(of: "POST ", with: "").replacingOccurrences(of: "DELETE ", with: "") let method = req.method.rawValue let baseurl = "https://fueling.prelub.com" let qstring = req.query let components: Dictionary = try req.query.decode(Dictionary.self) var startdate : Date? var qs: [String] = [] for component in components { qs.append( "\(component.key)=\(component.value ?? "nil")") } if(try qstring.get(String?.self, at: "startdate") != nil) { startdate = try parseDate2(qstring.get(String?.self, at: "startdate") ?? "") if(startdate == nil) { return try await(getMaximError(req, "startdate is invalid format. YYYY-MM-DD")) .encodeResponse(for: req) } } else { //throw error return try await getMaximError(req, "startdate is required").encodeResponse(for: req) } var enddate : Date?//= try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) if(try qstring.get(String?.self, at: "enddate") != nil) { enddate = try parseDate2(qstring.get(String?.self, at: "enddate") ?? "", false) if(enddate == nil) { return try await getMaximError(req, "enddate is invalid format. YYYY-MM-DD").encodeResponse(for: req) } } let page = try qstring.get(Int?.self, at: "page") ?? 1 let per = try qstring.get(Int?.self, at: "per") ?? 5 var records : Int = 0 if(enddate == nil) { records = try await FuelEntry.query(on: req.db) .field(\.$id) .group(.and) { grp in grp.filter(\.$loaddate >= startdate) .filter(\.$image != nil) } .all() .count } else { records = try await FuelEntry.query(on: req.db) .field(\.$id) .group(.and) { grp in grp.filter(\.$loaddate >= startdate) .filter(\.$image != nil) .filter(\.$loaddate <= enddate) } .all() .count } let qsStr = qs.joined(separator: "&") let paging = try await getPaging(page, per, records) let meta = Meta(page: page, per: per, total: records, lastpage: (paging["lastpage"] != nil) ? paging["lastpage"] as! Bool : false, error: false, message: "", method: method, baseurl: baseurl, route: rt, querystring: "?\(qsStr)") let query = try await FuelEntry.query(on: req.db) .field(\.$id) .field(\.$timestamp) .field(\.$userID) .field(\.$product) .field(\.$make) .field(\.$model) .field(\.$serialNumber) .field(\.$tankID) .field(\.$fuelAmount) .field(\.$fuelType) .field(\.$isOverride) .field(\.$latitude) .field(\.$longitude) .field(\.$downloaded) .field(\.$loaddate) .field(\.$image) .field(\.$tabletserial) .group(.and) { grp in if(enddate != nil) { grp.filter(\.$loaddate >= startdate) .filter(\.$image != nil) .filter(\.$loaddate <= enddate!) } else { grp.filter(\.$loaddate >= startdate) .filter(\.$image != nil) } } .sort(\.$loaddate, .ascending) .range(lower: (paging["offset"] as! Int), upper: (paging["offset"] as! Int) + (paging["per"] as! Int)) .all().map{ try FuelEntry.V2_1_Output.init(from: $0) } let response = returnObjV2_1(data: query, meta: meta) return try await response.encodeResponse(for: req) } @Sendable func filterTimeStamp(req: Request) async throws -> Response { let rt = req.route!.description.replacingOccurrences(of: "GET ", with: "").replacingOccurrences(of: "PUT ", with: "").replacingOccurrences(of: "POST ", with: "").replacingOccurrences(of: "DELETE ", with: "") let method = req.method.rawValue let baseurl = "https://fueling.prelub.com" let qstring = req.query let components: Dictionary = try req.query.decode(Dictionary.self) var startdate : Date? var qs: [String] = [] for component in components { qs.append( "\(component.key)=\(component.value ?? "nil")") } if(try qstring.get(String?.self, at: "startdate") != nil) { startdate = try parseDate2(qstring.get(String?.self, at: "startdate") ?? "") if(startdate == nil) { return try await(getMaximError(req, "startdate is invalid format. YYYY-MM-DD")) .encodeResponse(for: req) } } else { //throw error return try await getMaximError(req, "startdate is required").encodeResponse(for: req) } var enddate : Date?//= try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) if(try qstring.get(String?.self, at: "enddate") != nil) { enddate = try parseDate2(qstring.get(String?.self, at: "enddate") ?? "", false) if(enddate == nil) { return try await getMaximError(req, "enddate is invalid format. YYYY-MM-DD").encodeResponse(for: req) } } let emptyData: Data? = Data() let page = try qstring.get(Int?.self, at: "page") ?? 1 let per = try qstring.get(Int?.self, at: "per") ?? 10 let records = try await getCount(req, generateSQLNoImage(startdate ?? nil, enddate ?? nil) ) let paging = try await getPaging(page, per, records) let meta = Meta(page: page, per: per, total: records, lastpage: (paging["lastpage"] != nil) ? paging["lastpage"] as! Bool : false, error: false, message: "", method: method, baseurl: baseurl, route: rt, querystring: "?\(qs.joined(separator: "&"))") let query = try await FuelEntry.query(on: req.db) .field(\.$id) .field(\.$timestamp) .field(\.$userID) .field(\.$product) .field(\.$make) .field(\.$model) .field(\.$serialNumber) .field(\.$tankID) .field(\.$fuelAmount) .field(\.$fuelType) .field(\.$isOverride) .field(\.$latitude) .field(\.$longitude) .field(\.$downloaded) .field(\.$loaddate) .field(\.$tabletserial) .group(.and) { grp in grp.filter(\.$timestamp >= startdate ?? Calendar.current.startOfDay(for: Calendar.current.date(byAdding: .day, value: -2, to: Date())!)) if( enddate != nil) { grp.filter(\.$timestamp <= enddate!) } } .sort(\.$loaddate, .ascending) .range(lower: (paging["offset"] as! Int), upper: (paging["offset"] as! Int) + (paging["per"] as! Int)) .all().map{ try FuelEntry.V2_1_Output.init(from: $0) } let response = returnObjV2_1(data: query, meta: meta) return try await response.encodeResponse(for: req) } @Sendable func filtered(req: Request) async throws -> Response { let qstring = req.query let startdate = try parseDate(qstring.get(String?.self, at: "startdate") ?? "") let enddate = try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) let image = try qstring.get(Bool?.self, at: "image") ?? false let serial = try qstring.get(String?.self, at: "serial") ?? nil let tank = try qstring.get(String?.self, at: "tank") ?? nil let previous = try qstring.get(Bool?.self, at: "previous") ?? false var query = FuelEntry.query(on: req.db) if(image){ query = query .field(\.$id) .field(\.$timestamp) .field(\.$userID) .field(\.$product) .field(\.$make) .field(\.$model) .field(\.$serialNumber) .field(\.$tankID) .field(\.$fuelAmount) .field(\.$fuelType) .field(\.$isOverride) .field(\.$latitude) .field(\.$longitude) .field(\.$image) .field(\.$downloaded) .field(\.$loaddate) .field(\.$tabletserial) //.filter(\.$image != nil) } else { query = query .field(\.$id) .field(\.$timestamp) .field(\.$userID) .field(\.$product) .field(\.$make) .field(\.$model) .field(\.$serialNumber) .field(\.$tankID) .field(\.$fuelAmount) .field(\.$fuelType) .field(\.$isOverride) .field(\.$latitude) .field(\.$longitude) .field(\.$downloaded) .field(\.$tabletserial) .field(\.$loaddate) } query = query.group(.and){ grp in if( startdate != nil) { grp.filter(\.$loaddate >= startdate) } if( enddate != nil) { grp.filter(\.$loaddate <= enddate!) } if( serial != nil) { grp.filter(\.$serialNumber == serial!) } if( tank != nil) { grp.filter(\.$tankID == tank!) } if(!previous){ grp.filter(\.$pulldate == nil) } } query = query.sort(\.$loaddate, .ascending) if(image){ //query = query.filter(\.$image) let wimage = try await query.paginate(for: req).map{ img in FuelEntry.wimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, isOverride: img.isOverride, image: img.image == nil ? Data(): img.image, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: previous == true ? img.pulldate : Date()) } if(!previous){ wimage.items.forEach{ _ = $0.toFuelEntry().save(on: req.db) } } return try await wimage.encodeResponse(for: req) } else { let woimage = try await query.paginate(for: req).map{ img in FuelEntry.woimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, image: nil, isOverride: img.isOverride, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: previous == true ? img.pulldate : Date(), useremail: img.tabletserial) } if(!previous) { woimage.items.forEach { _ = $0.toFuelEntry().save(on: req.db) } } return try await woimage.encodeResponse(for: req) } } @Sendable func rpm(req: Request) async throws -> Response { let qstring = req.query let startdate = try parseDate(qstring.get(String?.self, at: "startdate") ?? "") let enddate = try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) let image = try qstring.get(Bool?.self, at: "image") ?? false let serial = try qstring.get(String?.self, at: "serial") ?? nil let tank = try qstring.get(String?.self, at: "tank") ?? nil let previous = try qstring.get(Bool?.self, at: "previous") ?? false var query = FuelEntry.query(on: req.db) if(image){ query = query .field(\.$id) .field(\.$timestamp) .field(\.$userID) .field(\.$product) .field(\.$make) .field(\.$model) .field(\.$serialNumber) .field(\.$tankID) .field(\.$fuelAmount) .field(\.$fuelType) .field(\.$isOverride) .field(\.$latitude) .field(\.$longitude) .field(\.$image) .field(\.$downloaded) .field(\.$loaddate) } else { query = query .field(\.$id) .field(\.$timestamp) .field(\.$userID) .field(\.$product) .field(\.$make) .field(\.$model) .field(\.$serialNumber) .field(\.$tankID) .field(\.$fuelAmount) .field(\.$fuelType) .field(\.$isOverride) .field(\.$latitude) .field(\.$longitude) .field(\.$downloaded) .field(\.$loaddate) } query = query.group(.and){ grp in if( startdate != nil) { grp.filter(\.$loaddate >= startdate!) } if( enddate != nil) { grp.filter(\.$loaddate <= enddate!) } if( serial != nil) { grp.filter(\.$serialNumber == serial!) } if( tank != nil) { grp.filter(\.$tankID == tank!) } if(!previous){ grp.filter(\.$pulldate == nil) } } query = query.sort(\.$loaddate, .ascending).sort(\.$timestamp).sort(\.$serialNumber) if(image){ //query = query.filter(\.$image) let wimage = try await query.paginate(for: req).map{ img in FuelEntry.wimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, isOverride: img.isOverride, image: img.image == nil ? Data(): img.image, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: Date()) } return try await wimage.encodeResponse(for: req) } else { let woimage = try await query.paginate(for: req).map{ img in FuelEntry.woimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, image: nil, isOverride: img.isOverride, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: Date(), useremail: img.tabletserial) } return try await woimage.encodeResponse(for: req) } } func create(req: Request) async throws -> Response { let fuelEntry = try req.content.decode([FuelEntry.V2_2_Input].self) var results: [FuelEntry] = [] for entry in fuelEntry { let uuid = entry.uniqueID let input = FuelEntry.init(from: entry) let exists = try await FuelEntry.query(on: req.db).filter(\.$uniqueID, .equal, uuid).first() if(exists == nil) { let data = entry.image ?? nil let length = data?.count if(data == nil || length == 0){ input.image = nil } if(entry.id != nil){ if (try await FuelEntry.find(entry.id!, on: req.db)) != nil { input._$id.exists = true } else { input._$idExists = false } } try await input.save(on: req.db) results.append(input) } else { results.append(exists!) } } // try await fuelEntry.create(on: req.db) let response = try await results.map{ try FuelEntry.V2_2_Output.init(from: $0) }.encodeResponse(for: req) return response } func delete(req: Request) async throws -> HTTPStatus { guard let fuelEntry = try await FuelEntry.find(req.parameters.get("fuelEntryID"), on: req.db) else { throw Abort(.notFound) } try await fuelEntry.delete(on: req.db) return .noContent } @Sendable func getrpm(req: Request) async throws -> Response { let qstring = req.query let startdate = try parseDate(qstring.get(String?.self, at: "startdate") ?? "") let enddate = try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) let image = try qstring.get(Bool?.self, at: "image") ?? false let serial = try qstring.get(String?.self, at: "serial") ?? nil let tank = try qstring.get(String?.self, at: "tank") ?? nil let previous = try qstring.get(Bool?.self, at: "previous") ?? false var query = FuelEntry.query(on: req.db) if(image){ query = query .field(\.$id) .field(\.$timestamp) .field(\.$userID) .field(\.$product) .field(\.$make) .field(\.$model) .field(\.$serialNumber) .field(\.$tankID) .field(\.$fuelAmount) .field(\.$fuelType) .field(\.$isOverride) .field(\.$latitude) .field(\.$longitude) .field(\.$image) .field(\.$downloaded) .field(\.$loaddate) } else { query = query .field(\.$id) .field(\.$timestamp) .field(\.$userID) .field(\.$product) .field(\.$make) .field(\.$model) .field(\.$serialNumber) .field(\.$tankID) .field(\.$fuelAmount) .field(\.$fuelType) .field(\.$isOverride) .field(\.$latitude) .field(\.$longitude) .field(\.$downloaded) .field(\.$loaddate) } query = query.group(.and){ grp in if( startdate != nil) { grp.filter(\.$loaddate >= startdate!) } if( enddate != nil) { grp.filter(\.$loaddate <= enddate!) } if( serial != nil) { grp.filter(\.$serialNumber == serial!) } if( tank != nil) { grp.filter(\.$tankID == tank!) } if(!previous){ grp.filter(\.$pulldate == nil) } } query = query.sort(\.$loaddate, .ascending).sort(\.$timestamp).sort(\.$serialNumber) if(image){ //query = query.filter(\.$image) let wimage = try await query.paginate(for: req).map{ img in FuelEntry.wimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, isOverride: img.isOverride, image: img.image == nil ? Data(): img.image, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: Date()) } return try await wimage.encodeResponse(for: req) } else { let woimage = try await query.paginate(for: req).map{ img in FuelEntry.woimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, image: nil, isOverride: img.isOverride, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: Date(), useremail: img.tabletserial) } return try await woimage.encodeResponse(for: req) } } } //struct custMeta: Content { // let per: Int // let page: Int // let total: Int // let status: String? //} // //struct PageRequest: Content { // var page: Int // var size: Int // var status: String? // // Add any other properties needed for pagination // // init(page: Int, size: Int, status: String? = nil) { // self.page = page // self.size = size // self.status = status // } //}