From 27275672821fe1e9dc87e43b9a09e8c97ef07e43 Mon Sep 17 00:00:00 2001
From: Ramakrishnan Muthukrishnan <ram@leastauthority.com>
Date: Thu, 17 Oct 2019 19:04:08 +0530
Subject: [PATCH] persistence: new function to get all paid but unredeemed
 vouchers

Use this function to check if the given voucher is unpaid. Perhaps
this can be done in Sql itself without resorting to set operations.
---
 src/PaymentServer/Persistence.hs | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/PaymentServer/Persistence.hs b/src/PaymentServer/Persistence.hs
index 3009119..19bda64 100644
--- a/src/PaymentServer/Persistence.hs
+++ b/src/PaymentServer/Persistence.hs
@@ -14,6 +14,7 @@ import Control.Monad
   )
 import Data.Text
   ( Text
+  , unpack
   )
 import qualified Data.Set as Set
 import qualified Data.Map as Map
@@ -116,7 +117,7 @@ instance VoucherDatabase Sqlite.Connection where
     undefined
   -- redeemVoucher :: Sqlite.Connection -> Voucher -> Fingerprint -> IO (Either RedeemError ())
   redeemVoucher dbConn voucher fingerprint = do
-    unpaid <- Set.notMember voucher <$> getPaidVouchers dbConn
+    unpaid <- Set.notMember voucher <$> (Set.fromList <$> getUnredeemedVouchers dbConn)
     existingFingerprint <- getVoucherFingerprint dbConn voucher
     case (unpaid, existingFingerprint) of
       (True, _) ->
@@ -133,9 +134,10 @@ instance VoucherDatabase Sqlite.Connection where
 instance FromRow Fingerprint where
   fromRow = Sqlite.field
 
-getPaidVouchers :: Sqlite.Connection -> IO (Set.Set Voucher)
-getPaidVouchers dbConn = Set.fromList <$>
-  Sqlite.query_ dbConn "SELECT DISTINCT name FROM vouchers"
+-- | Paid but not redeemed
+getUnredeemedVouchers :: Sqlite.Connection -> IO [Voucher]
+getUnredeemedVouchers dbConn =
+  Sqlite.query_ dbConn "SELECT DISTINCT NAME FROM vouchers INNER JOIN redeemed_new WHERE vouchers.id != redeemed.voucher_id"
 
 getVoucherFingerprint :: Sqlite.Connection -> Voucher -> IO [Fingerprint]
 getVoucherFingerprint dbConn voucher = do
@@ -143,6 +145,6 @@ getVoucherFingerprint dbConn voucher = do
 
 getDBConnection :: Text -> IO ()
 getDBConnection name = do
-  dbConn <- Sqlite.open name
-  Sqlite.execute_ dbConn "CREATE TABLE IF NOT EXISTS vouchers (id INTEGER PRIMARY KEY, name TEXT)"
+  dbConn <- Sqlite.open (unpack name)
+  Sqlite.execute_ dbConn "CREATE TABLE IF NOT EXISTS vouchers (id INTEGER PRIMARY KEY, name TEXT UNIQUE"
   Sqlite.execute_ dbConn "CREATE TABLE IF NOT EXISTS redeemed (id INTEGER PRIMARY KEY, voucher_id INTEGER, fingerprint TEXT, FOREIGN KEY (voucher_id) REFERENCES vouchers(id))"
-- 
GitLab