@@ -35,6 +35,31 @@ class MerchantDAO: PointOfUseDAO {
3535 connection = dbConnection
3636 }
3737
38+ /// Extracts sourceId from a database row, handling String, Int64, Int types and nil/empty values
39+ /// - Parameters:
40+ /// - row: The database row (Statement.Element)
41+ /// - index: The column index for sourceId
42+ /// - Returns: The sourceId as a String, or nil if missing/empty/invalid
43+ private func extractSourceId( from row: Statement . Element , at index: Int ) -> String ? {
44+ guard row. count > index else { return nil }
45+
46+ if let sourceId = row [ index] as? String , !sourceId. isEmpty {
47+ return sourceId
48+ } else if let sourceId = row [ index] as? Int64 {
49+ return String ( sourceId)
50+ } else if let sourceId = row [ index] as? Int {
51+ return String ( sourceId)
52+ } else if let sourceId = row [ index] {
53+ let stringValue = String ( describing: sourceId)
54+ if stringValue == " <null> " || stringValue == " nil " {
55+ return nil
56+ }
57+ return stringValue
58+ }
59+
60+ return nil
61+ }
62+
3863 func items( filters: PointOfUseDAOFilters , offset: Int ? ,
3964 completion: @escaping ( Swift . Result < PaginationResult < Item > , Error > ) -> Void ) { }
4065
@@ -180,7 +205,7 @@ class MerchantDAO: PointOfUseDAO {
180205 // Only fetch CTX providers when PiggyCards is disabled
181206 #if PIGGYCARDS_ENABLED
182207 let providersQuery = """
183- SELECT provider, savingsPercentage, denominationsType FROM gift_card_providers
208+ SELECT provider, savingsPercentage, denominationsType, sourceId FROM gift_card_providers
184209 WHERE merchantId = ' \( merchant. merchantId) '
185210 """
186211 #else
@@ -192,21 +217,23 @@ class MerchantDAO: PointOfUseDAO {
192217
193218 do {
194219 guard let db = wSelf. connection. db else {
195- print ( " Error: Database connection is nil for merchant \( merchant. merchantId) " )
196220 continue
197221 }
198-
199222 let rows = try db. prepare ( providersQuery)
200223 var providers : [ ExplorePointOfUse . Merchant . GiftCardProviderInfo ] = [ ]
224+ var rowCount = 0
201225
202226 for row in rows {
227+ rowCount += 1
203228 if let providerId = row [ 0 ] as? String ,
204229 let savingsPercentage = row [ 1 ] as? Int64 ,
205230 let denominationsType = row [ 2 ] as? String {
231+
206232 providers. append ( ExplorePointOfUse . Merchant. GiftCardProviderInfo (
207233 providerId: providerId,
208234 savingsPercentage: Int ( savingsPercentage) ,
209- denominationsType: denominationsType
235+ denominationsType: denominationsType,
236+ sourceId: wSelf. extractSourceId ( from: row, at: 3 )
210237 ) )
211238 }
212239 }
@@ -249,7 +276,7 @@ class MerchantDAO: PointOfUseDAO {
249276 allItems [ index] = updatedItem
250277 }
251278 } catch {
252- print ( " Error fetching gift card providers for merchant \( merchant . merchantId ) : \( error ) " )
279+ // Error fetching gift card providers
253280 }
254281 }
255282 }
@@ -410,7 +437,7 @@ class MerchantDAO: PointOfUseDAO {
410437 // Only fetch CTX providers when PiggyCards is disabled
411438 #if PIGGYCARDS_ENABLED
412439 let providersQuery = """
413- SELECT provider, savingsPercentage, denominationsType FROM gift_card_providers
440+ SELECT provider, savingsPercentage, denominationsType, sourceId FROM gift_card_providers
414441 WHERE merchantId = ' \( merchant. merchantId) '
415442 """
416443 #else
@@ -422,25 +449,29 @@ class MerchantDAO: PointOfUseDAO {
422449
423450 do {
424451 guard let db = wSelf. connection. db else {
425- print ( " Error: Database connection is nil for merchant \( merchant. merchantId) " )
426452 continue
427453 }
428454
429455 let rows = try db. prepare ( providersQuery)
430456 var providers : [ ExplorePointOfUse . Merchant . GiftCardProviderInfo ] = [ ]
431-
457+ var rowCount = 0
458+
432459 for row in rows {
460+ rowCount += 1
433461 if let providerId = row [ 0 ] as? String ,
434462 let savingsPercentage = row [ 1 ] as? Int64 ,
435463 let denominationsType = row [ 2 ] as? String {
464+
436465 providers. append ( ExplorePointOfUse . Merchant. GiftCardProviderInfo (
437466 providerId: providerId,
438467 savingsPercentage: Int ( savingsPercentage) ,
439- denominationsType: denominationsType
468+ denominationsType: denominationsType,
469+ sourceId: wSelf. extractSourceId ( from: row, at: 3 )
440470 ) )
441471 }
442472 }
443-
473+
474+
444475 if !providers. isEmpty {
445476 // Create updated merchant with providers
446477 let updatedMerchant = ExplorePointOfUse . Merchant (
@@ -480,11 +511,10 @@ class MerchantDAO: PointOfUseDAO {
480511 }
481512 } catch {
482513 // If we can't fetch providers, just continue with empty providers
483- print ( " Error fetching gift card providers for merchant \( merchant. merchantId) : \( error) " )
484514 }
485515 }
486516 }
487-
517+
488518 completion ( . success( PaginationResult ( items: items, offset: offset) ) )
489519 } catch {
490520 print ( error)
@@ -583,59 +613,59 @@ extension MerchantDAO {
583613 let boundsRadius = min ( latDiff, lonDiff) * 111000 / 2 // Convert degrees to meters, divide by 2
584614 let filterRadius = boundsRadius
585615
586- print ( " 🎯 MerchantDAO.allLocations: Applying circular distance filter with radius= \( filterRadius) m ( \( filterRadius/ 1609.34 ) miles) " )
587616
588617 let initialCount = items. count
589618 items = items. filter { item in
590619 guard let lat = item. latitude, let lon = item. longitude else { return false }
591620 let distance = userCLLocation. distance ( from: CLLocation ( latitude: lat, longitude: lon) )
592621 let isWithinRadius = distance <= filterRadius
593622 if !isWithinRadius {
594- print ( " 🎯 MerchantDAO.allLocations: Filtering out ' \( item. name) ' at \( distance/ 1609.34 ) miles (outside \( filterRadius/ 1609.34 ) mile radius) " )
595623 }
596624 return isWithinRadius
597625 }
598626
599- print ( " 🎯 MerchantDAO.allLocations: After circular distance filtering: \( items. count) locations remain (was \( initialCount) ) " )
600627 }
601628
602629 // Fetch gift card provider information for gift card merchants
603630 for (index, item) in items. enumerated ( ) {
604631 if let merchant = item. merchant, merchant. paymentMethod == . giftCard {
605- // Only fetch CTX providers when PiggyCards is disabled
606- #if PIGGYCARDS_ENABLED
632+ // Use parameterized query to avoid SQL injection
607633 let providersQuery = """
608- SELECT provider, savingsPercentage, denominationsType FROM gift_card_providers
609- WHERE merchantId = ' \( merchant . merchantId ) '
634+ SELECT provider, savingsPercentage, denominationsType, sourceId FROM gift_card_providers
635+ WHERE merchantId = ?
610636 """
611- #else
612- let providersQuery = """
613- SELECT provider, savingsPercentage, denominationsType FROM gift_card_providers
614- WHERE merchantId = ' \( merchant. merchantId) ' AND provider = 'CTX'
615- """
616- #endif
617637
618638 do {
619639 guard let db = wSelf. connection. db else {
620640 print ( " Error: Database connection is nil for merchant \( merchant. merchantId) " )
621641 continue
622642 }
623643
624- let rows = try db. prepare ( providersQuery)
644+ let statement = try db. prepare ( providersQuery, merchant . merchantId )
625645 var providers : [ ExplorePointOfUse . Merchant . GiftCardProviderInfo ] = [ ]
646+ var rowCount = 0
647+
648+ for row in statement {
649+ rowCount += 1
650+ // Access columns by index
651+ let providerId = row [ 0 ] as? String
652+ let savingsPercentage = row [ 1 ] as? Int64
653+ let denominationsType = row [ 2 ] as? String
654+
655+ if let providerId = providerId,
656+ let savingsPercentage = savingsPercentage,
657+ let denominationsType = denominationsType {
626658
627- for row in rows {
628- if let providerId = row [ 0 ] as? String ,
629- let savingsPercentage = row [ 1 ] as? Int64 ,
630- let denominationsType = row [ 2 ] as? String {
631659 providers. append ( ExplorePointOfUse . Merchant. GiftCardProviderInfo (
632660 providerId: providerId,
633661 savingsPercentage: Int ( savingsPercentage) ,
634- denominationsType: denominationsType
662+ denominationsType: denominationsType,
663+ sourceId: wSelf. extractSourceId ( from: row, at: 3 )
635664 ) )
636665 }
637666 }
638667
668+
639669 if !providers. isEmpty {
640670 // Create updated merchant with providers
641671 let updatedMerchant = ExplorePointOfUse . Merchant (
0 commit comments