Skip to content

Instantly share code, notes, and snippets.

@decapo01
Last active April 29, 2020 01:12
Show Gist options
  • Save decapo01/ac4ce01d68dc334108073ef6b38020dc to your computer and use it in GitHub Desktop.
Save decapo01/ac4ce01d68dc334108073ef6b38020dc to your computer and use it in GitHub Desktop.
Repository Service Pattern With Cache
//User
User {
id: UserId
username: String
}
//UserDetails
UserDetails {
otherDetails: String
}
//UserWithDetails
UserWithDetails {
id: UserId,
username: String,
otherDetails: String
}
//UserService
UserService {
userRepo: UserRepo // <- if you want to use oo injection
construct(userRepo: UserRepo){
this.userRepo = userRepo
}
findUser(userId: UserId): Option<UserWithDetails> {
return userRepo.find(userId)
}
// Functional Style. Can be Static
static fetchUsers(repoFetchUser: () -> Array<User>): Array<User> {
return repoFetchUser()
}
}
//UserRepo OO
interface UserWithDetailsRepo {
find(userId: UserId): Option<UserWithDetails>
}
//UserArangoRepo
UserArangoRepo {
// Just gets user since that's all thats in arango
find(userId: UserId): Option<User> {
return fetchEntities<User>("users") |> find u -> u.userId == userId
}
}
//UserDetailsRepo
UserDetailsRepo {
find(userId: UserId): Option<UserDetail> {
return fetchEntities<Notification>("notification")
|> find u -> u.userId == userid
|> map
|> mapToUserDetail
}
}
//UserWithDetailsRedisRepo
UserWithDetailsRedisRepo {
find(userId: UserId): Option<UserWithDetail> {
return redis.get('userWithDetails', userId)
}
insert(userWithDetails: UserWithDetailsRepo): Void {
redis.insert(userWithDetails.id, userWithDetails)
}
}
//UserWithDetailsRepoImplementation
UserWithDetailsRepoImpl implements UserWithDetailsRepo {
// You can inject if you want here to make switching out components easier
// in the future but it's not necessary for the core logic of you application
find(userId: UserId): Option<UserWithDetail> {
userFromCache = UserWithDetailsRedisRepo.find(userId)
match(userFromCache){
Some u -> return Some u
None ->
userFromArango = UserArangoRepo.find(userId)
userDetails = UserDetailsRepo.find(userId)
match ((userFromArango,userDetails)) {
(Some user, Some details) -> return Some(mapToUserWithDetails(user,details))
_ -> return None
}
}
}
}
//Makes a lot more sense in this context
UserService {
userRepo: UserRepo // <- if you want to use oo injection
construct(userRepo: UserRepo){
this.userRepo = userRepo
}
findUser(userId: UserId): Option<UserWithDetails> {
return userRepo.find(userId)
}
// Functional Style. Can be Static
static fetchUser(repoFetchUser: () -> Option<User>): Option<User> {
return repoFetchUser()
}
static registerUser(email : String,
password : String,
confirmPassword : String,
otherDetail : String
repoFindUserByEmail : (String) -> Option<User>,
repoInsertUser : (UserWithDetails) -> Either<Error,UserWithDetails>,
hashPassword : (String) -> String) : Either<Error,UserWithDetails>) {
userEither = validateUser(email,password,confirmPassword,otherDetails)
match userEither
Left e -> return Left(e)
Right userWithDetails ->
match findUserByEmail(userWithDetails.email)
Some u -> return Left(UserExists)
None ->
match hashPassword(userWithDetails.password)
Left e -> return Left(e)
Right hashedPassword ->
match insertUser(userWithDetails.copy(password = hashPassword))
Left e -> return Left(e)
Right savedUserWithDetails -> return Right(savedUserWithDetails)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment