2020-07-03 13:05:23 +02:00
package nouritsu ;
2020-07-04 00:38:18 +02:00
import io.vavr.collection.HashSet ;
2020-07-05 00:20:47 +02:00
import io.vavr.collection.List ;
2020-07-03 13:05:23 +02:00
import io.vavr.control.Either ;
2020-07-05 00:20:47 +02:00
import io.vavr.control.Option ;
2020-07-04 00:38:18 +02:00
import nouritsu.types.Resp ;
import nouritsu.types.Section ;
import nouritsu.types.ShoppingItem ;
import nouritsu.types.Store ;
import redis.clients.jedis.Jedis ;
import redis.clients.jedis.JedisPool ;
2020-07-03 13:05:23 +02:00
2020-07-04 00:38:18 +02:00
import java.util.function.Function ;
2020-07-03 13:05:23 +02:00
2020-07-09 21:57:51 +02:00
import static nouritsu.Serde.deserialize ;
import static nouritsu.Serde.serialize ;
2020-07-03 13:05:23 +02:00
public class Dao {
2020-07-04 00:38:18 +02:00
private final JedisPool pool ;
2020-07-05 00:20:47 +02:00
// Prefixes for the redis keys because other applications might also be using the redis
private static final String PREFIX = " nouritsu_ " ;
private static final String USER_PREFIX = PREFIX + " user_ " ;
private static final String STORE_PREFIX = PREFIX + " store_ " ;
private static final String ITEM_PREFIX = PREFIX + " item_ " ;
2020-07-04 00:38:18 +02:00
Dao ( ) {
pool = new JedisPool ( ) ;
}
private < T > T withRedis ( Function < Jedis , T > f ) {
try ( var redis = pool . getResource ( ) ) {
return f . apply ( redis ) ;
}
}
2020-07-05 00:20:47 +02:00
private Option < ShoppingItem > getItem ( String name ) {
return Option . of ( withRedis ( redis - > redis . get ( ITEM_PREFIX + name ) ) )
2020-07-09 21:57:51 +02:00
. map ( item - > deserialize ( item , ShoppingItem . class ) ) ;
2020-07-05 00:20:47 +02:00
}
2020-07-04 00:38:18 +02:00
public String clearList ( String id ) {
2020-07-05 00:20:47 +02:00
withRedis ( redis - > redis . del ( USER_PREFIX + id ) ) ;
2020-07-04 00:38:18 +02:00
// Just always return okay, even if we didn’t have data to begin with.
// Idempotency yay \o/
2020-07-09 21:57:51 +02:00
return created ( " Cleared list of user “%s“ " ) . formatted ( id ) ;
2020-07-04 00:38:18 +02:00
}
2020-07-05 00:27:39 +02:00
// The .exists() check is necessary because smembers throws an exception instead of returning null or an empty set.
2020-07-05 00:20:47 +02:00
private Option < HashSet < String > > getSet ( String key ) {
2020-07-04 00:38:18 +02:00
return withRedis ( redis - >
2020-07-05 00:20:47 +02:00
redis . exists ( key )
? Option . some ( HashSet . ofAll ( redis . smembers ( key ) ) )
: Option . none ( )
) ;
}
public Either < Resp , HashSet < ShoppingItem > > getList ( String id ) {
return getSet ( USER_PREFIX + id )
. map ( items - > items . map ( this : : getItem ) . map ( Option : : get ) )
. toEither ( Resp . NOT_FOUND . apply ( " No list found for user “%s” " . formatted ( id ) ) ) ;
}
public Either < Resp , Store > getStore ( String name ) {
2020-07-09 21:57:51 +02:00
return withRedis ( redis - > Option . of ( redis . get ( STORE_PREFIX + name ) ) )
2020-07-05 00:20:47 +02:00
. toEither ( Resp . BAD_REQUEST . apply ( " Store %s not found " . formatted ( name ) ) )
2020-07-09 21:57:51 +02:00
. map ( s - > deserialize ( s , Store . class ) ) ;
2020-07-04 00:38:18 +02:00
}
2020-07-05 00:20:47 +02:00
// Check if an item is known and add it to the list if it is.
2020-07-04 00:38:18 +02:00
public Either < Resp , String > addToList ( String id , String item ) {
2020-07-05 00:20:47 +02:00
return getItem ( item ) . map ( it - > {
withRedis ( redis - > redis . sadd ( USER_PREFIX + id , item ) ) ;
2020-07-09 21:57:51 +02:00
return created ( " Added “%s“ to list of user “%s” " ) . formatted ( it , id ) ;
2020-07-05 00:20:47 +02:00
} ) . toEither ( Resp . BAD_REQUEST . apply ( " Item %s not found " . formatted ( item ) ) ) ;
2020-07-04 00:38:18 +02:00
}
public String addItem ( ShoppingItem item ) {
2020-07-09 21:57:51 +02:00
withRedis ( redis - > redis . set ( ITEM_PREFIX + item . name ( ) , serialize ( item ) ) ) ;
return created ( " Registered new item “%s” under the section “%s” " )
2020-07-04 00:38:18 +02:00
. formatted ( item . name ( ) , item . section ( ) . name ( ) . toLowerCase ( ) ) ;
2020-07-03 13:05:23 +02:00
}
2020-07-09 21:57:51 +02:00
private String created ( String msg ) {
return " { \" msg \" : \" %s \" } " . formatted ( msg ) ;
}
2020-07-05 00:20:47 +02:00
public String addStore ( Store store ) {
// just overwrite it if we already know that store
2020-07-05 00:38:43 +02:00
withRedis ( redis - >
2020-07-09 21:57:51 +02:00
redis . del ( STORE_PREFIX + store . name ( ) )
// This plus doesn’t actually add anything.
2020-07-05 00:38:43 +02:00
// It just allows us to do both steps in one statement in the lambda body.
2020-07-09 21:57:51 +02:00
+ redis . set ( STORE_PREFIX + store . name ( ) , serialize ( store ) )
2020-07-05 00:20:47 +02:00
) ;
2020-07-09 21:57:51 +02:00
return created ( " Registered new store “%s” with the sections [%s] " ) . formatted ( store . name ( ) , store . sections ( ) ) ;
2020-07-03 13:05:23 +02:00
}
}