-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Crud #6
Open
0xck
wants to merge
3
commits into
senia-otus:master
Choose a base branch
from
0xck:CRUD
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Crud #6
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,209 @@ | ||
package ru.otus.sc | ||
|
||
import ru.otus.sc.greet.dao.impl.GreetingDaoImpl | ||
import ru.otus.sc.Engine.{Greeted, StorageKey, StorageValue} | ||
import ru.otus.sc.countdown.model._ | ||
import ru.otus.sc.counter.model._ | ||
import ru.otus.sc.echo.model.{EchoRequest, EchoResponse} | ||
import ru.otus.sc.greet.model.{GreetRequest, GreetResponse} | ||
import ru.otus.sc.greet.service.GreetingService | ||
import ru.otus.sc.greet.service.impl.GreetingServiceImpl | ||
import ru.otus.sc.reverse.model.{ReverseRequest, ReverseResponse} | ||
import ru.otus.sc.storage.model._ | ||
import ru.otus.sc.sum.model.{SumRequest, SumResponse} | ||
import ru.otus.sc.user.model._ | ||
|
||
trait App { | ||
def greet(request: GreetRequest): GreetResponse | ||
// reply on requested value with the same value | ||
// echo value can be multiplied up to 5 times with `repeatNum` value | ||
// no multiply answer by default (`repeatNum` is 1) | ||
// proper values return answer with `EchoAnswerResponse` | ||
// bad values return error with `EchoErrorResponse` | ||
def echo(request: EchoRequest): EchoResponse | ||
// greet with provided object | ||
// panic if `isHuman` flag is unset | ||
// greeting request requires implicit parameter for extracting name from the object | ||
// in current implementation object is User and implicit can be borrowed from | ||
// `ru.otus.sc.user.implicits.UserNameImplicits._` | ||
def greet(request: GreetRequest[Greeted]): GreetResponse | ||
// reverse given string from end to begin | ||
def reverse(request: ReverseRequest): ReverseResponse | ||
// sum 2 given values locally | ||
// sum can be performed externally with `external` flag | ||
// in current implementation external computation is artificial delay | ||
// which was implemented with lazy value | ||
def sum(request: SumRequest): SumResponse | ||
// manage users | ||
// user is compound from: | ||
// id, which is DB related stuff like pk | ||
// unique id, UUID, this item is unique for whole system | ||
// user name, which is compound from: first, last, middle, patronymic names and title | ||
// age | ||
// set of tags | ||
// CRUD operations are available as well as search for first, last name and tag | ||
def createUser(request: CreateUserRequest): CreateUserResponse | ||
def getUser(request: GetUserRequest): GetUserResponse | ||
def deleteUser(request: DeleteUserRequest): DeleteUserResponse | ||
def updateUser(request: UpdateUserRequest): UpdateUserResponse | ||
def findUsers(request: FindUsersRequest): FindUsersResponse | ||
// manage user tags | ||
// tags are bound with users and related only them | ||
// tag is compound from: | ||
// id, which is DB related stuff like pk | ||
// name, for human | ||
// CRUD operations are available as well as search for name | ||
// also associated with certain tag users can be obtained in search request | ||
// tags and users are totally independent | ||
// tagging and untagging users do not allow manage tags on users directly | ||
// and have to be performed as separate operations for users and tags | ||
// e.g. tagging user example, | ||
// imagine we already have app, user, tag and all operations are done successfully: | ||
// val tagId = 42L | ||
// val uniqueUserId = UUID.fromString("4a71a58b-4b39-44fc-ae52-76b9657be280") | ||
// val tag = app.getUserTag(GetUserTagRequest(tagId)) | ||
// val user = app.getUser(GetUserRequest(uniqueUserId)) | ||
// val updatedUser = user.copy(tags = (user.tags + tag)) | ||
// app.tagUser(UpdateTagUserRequest(tagId, uniqueUserId)) | ||
// app.updateUser(UpdateUserRequest(updatedUser)) | ||
def createUserTag(request: CreateUserTagRequest): CreateUserTagResponse | ||
def getUserTag(request: GetUserTagRequest): GetUserTagResponse | ||
def deleteUserTag(request: DeleteUserTagRequest): DeleteUserTagResponse | ||
def updateUserTag(request: UpdateUserTagRequest): UpdateUserTagResponse | ||
def findUserTags(request: FindUserTagsRequest): FindUserTagsResponse | ||
def tagUser(request: UpdateTagUserRequest): UpdateTagUserResponse | ||
def untagUser(request: UpdateUntagUserRequest): UpdateUntagUserResponse | ||
// manage counters | ||
// counter is auto-increment item with initial `value`, default value is 1 | ||
// update increments counter by 1 | ||
// counter value can not be updated itself, it can be only incremented | ||
// timestamp is updated on every counter update | ||
// counter is compound from: | ||
// id, UUID, this item is unique for whole system | ||
// timestamp of update | ||
// value of counter | ||
// CRUD operations are available as well as search for values or timestamps | ||
// searching requires predicate (t: T, i: T) => Boolean for comparing items | ||
// where `t` is target and `i` is item in DB | ||
def createCounter(request: CreateCounterRequest): CreateCounterResponse | ||
def deleteCounter(request: DeleteCounterRequest): DeleteCounterResponse | ||
def updateCounter(request: UpdateCounterRequest): UpdateCounterResponse | ||
def getCounter(request: GetCounterRequest): GetCounterResponse | ||
def findCounters(request: FindCountersRequest): FindCountersResponse | ||
// manage countdowns | ||
// countdown is auto-decrement item with initial `value`, default value is 1 | ||
// update auto-decreases value by 1 | ||
// when countdown reaches 0 it stops decrease value and swaps state from Tick to Done | ||
// Countdown.Done is composed from id, UUID, this item is unique for whole system | ||
// State above can not be updated anymore, also it can be created `CountdownDone` | ||
// Countdown.Tick is composed from: | ||
// id, UUID, this item is unique for whole system | ||
// updater, UUID this is id of something that create or update countdown | ||
// value of countdown | ||
// CRUD operations are available as well as search for: | ||
// values, updaters, Done and NonDone states | ||
// searching for values requires predicate (t: T, i: T) => Boolean for comparing items | ||
// where `t` is target and `i` is item in DB | ||
def createCountdown(request: CreateCountdownRequest): CreateCountdownResponse | ||
def deleteCountdown(request: DeleteCountdownRequest): DeleteCountdownResponse | ||
def updateCountdown(request: UpdateCountdownRequest): UpdateCountdownResponse | ||
def getCountdown(request: GetCountdownRequest): GetCountdownResponse | ||
def findCountdowns(request: FindCountdownsRequest): FindCountdownsResponse | ||
// manage storage | ||
// provide value by requested key | ||
// StorageEntry is composed from key and value of defined types | ||
// in current implementation keys and values are String | ||
// CRUD operations are available as well as search for value itself or predicate on value | ||
// searching with predicate requires predicate i: V => Boolean for comparing items | ||
// where `i` is item in DB | ||
def createStorage( | ||
request: CreateStorageRequest[StorageKey, StorageValue] | ||
): CreateStorageResponse[StorageKey, StorageValue] | ||
def getStorage( | ||
request: GetStorageRequest[StorageKey, StorageValue] | ||
): GetStorageResponse[StorageKey, StorageValue] | ||
def deleteStorage( | ||
request: DeleteStorageRequest[StorageKey, StorageValue] | ||
): DeleteStorageResponse[StorageKey, StorageValue] | ||
def updateStorage( | ||
request: UpdateStorageRequest[StorageKey, StorageValue] | ||
): UpdateStorageResponse[StorageKey, StorageValue] | ||
def findStorages( | ||
request: FindStoragesRequest[StorageKey, StorageValue] | ||
): FindStoragesResponse[StorageKey, StorageValue] | ||
} | ||
|
||
object App { | ||
private class AppImpl(greeting: GreetingService) extends App { | ||
def greet(request: GreetRequest): GreetResponse = greeting.greet(request) | ||
} | ||
def apply(): App = new AppImpl(Engine()) | ||
|
||
def apply(): App = { | ||
val greetingDao = new GreetingDaoImpl | ||
val greetingService = new GreetingServiceImpl(greetingDao) | ||
new AppImpl(greetingService) | ||
private class AppImpl(engine: Engine) extends App { | ||
def echo(request: EchoRequest): EchoResponse = | ||
engine.echoing.echo(request) | ||
def greet(request: GreetRequest[Greeted]): GreetResponse = | ||
engine.greeting.greet(request) | ||
def reverse(request: ReverseRequest): ReverseResponse = | ||
engine.reversing.reverse(request) | ||
def sum(request: SumRequest): SumResponse = | ||
engine.summing.sum(request) | ||
def createUser(request: CreateUserRequest): CreateUserResponse = | ||
engine.usering.createUser(request) | ||
def getUser(request: GetUserRequest): GetUserResponse = | ||
engine.usering.getUser(request) | ||
def deleteUser(request: DeleteUserRequest): DeleteUserResponse = | ||
engine.usering.deleteUser(request) | ||
def updateUser(request: UpdateUserRequest): UpdateUserResponse = | ||
engine.usering.updateUser(request) | ||
def findUsers(request: FindUsersRequest): FindUsersResponse = | ||
engine.usering.findUsers(request) | ||
def createUserTag(request: CreateUserTagRequest): CreateUserTagResponse = | ||
engine.userTagging.createUserTag(request) | ||
def getUserTag(request: GetUserTagRequest): GetUserTagResponse = | ||
engine.userTagging.getUserTag(request) | ||
def deleteUserTag(request: DeleteUserTagRequest): DeleteUserTagResponse = | ||
engine.userTagging.deleteUserTag(request) | ||
def updateUserTag(request: UpdateUserTagRequest): UpdateUserTagResponse = | ||
engine.userTagging.updateUserTag(request) | ||
def findUserTags(request: FindUserTagsRequest): FindUserTagsResponse = | ||
engine.userTagging.findUserTags(request) | ||
def tagUser(request: UpdateTagUserRequest): UpdateTagUserResponse = | ||
engine.userTagging.tagUser(request) | ||
def untagUser(request: UpdateUntagUserRequest): UpdateUntagUserResponse = | ||
engine.userTagging.untagUser(request) | ||
def createCounter(request: CreateCounterRequest): CreateCounterResponse = | ||
engine.counting.createCounter(request) | ||
def deleteCounter(request: DeleteCounterRequest): DeleteCounterResponse = | ||
engine.counting.deleteCounter(request) | ||
def updateCounter(request: UpdateCounterRequest): UpdateCounterResponse = | ||
engine.counting.updateCounter(request) | ||
def getCounter(request: GetCounterRequest): GetCounterResponse = | ||
engine.counting.getCounter(request) | ||
def findCounters(request: FindCountersRequest): FindCountersResponse = | ||
engine.counting.findCounters(request) | ||
def createCountdown(request: CreateCountdownRequest): CreateCountdownResponse = | ||
engine.countdowning.createCountdown(request) | ||
def deleteCountdown(request: DeleteCountdownRequest): DeleteCountdownResponse = | ||
engine.countdowning.deleteCountdown(request) | ||
def updateCountdown(request: UpdateCountdownRequest): UpdateCountdownResponse = | ||
engine.countdowning.updateCountdown(request) | ||
def getCountdown(request: GetCountdownRequest): GetCountdownResponse = | ||
engine.countdowning.getCountdown(request) | ||
def findCountdowns(request: FindCountdownsRequest): FindCountdownsResponse = | ||
engine.countdowning.findCountdowns(request) | ||
def createStorage( | ||
request: CreateStorageRequest[StorageKey, StorageValue] | ||
): CreateStorageResponse[StorageKey, StorageValue] = | ||
engine.getting.createStorage(request) | ||
def deleteStorage( | ||
request: DeleteStorageRequest[StorageKey, StorageValue] | ||
): DeleteStorageResponse[StorageKey, StorageValue] = | ||
engine.getting.deleteStorage(request) | ||
def updateStorage( | ||
request: UpdateStorageRequest[StorageKey, StorageValue] | ||
): UpdateStorageResponse[StorageKey, StorageValue] = | ||
engine.getting.updateStorage(request) | ||
def getStorage( | ||
request: GetStorageRequest[StorageKey, StorageValue] | ||
): GetStorageResponse[StorageKey, StorageValue] = | ||
engine.getting.getStorage(request) | ||
def findStorages( | ||
request: FindStoragesRequest[StorageKey, StorageValue] | ||
): FindStoragesResponse[StorageKey, StorageValue] = | ||
engine.getting.findStorages(request) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package ru.otus.sc | ||
|
||
import ru.otus.sc.Engine.{Greeted, StorageKey, StorageValue} | ||
import ru.otus.sc.countdown.dao.impl.CountdownDaoImpl | ||
import ru.otus.sc.countdown.service.CountdownService | ||
import ru.otus.sc.countdown.service.impl.CountdownServiceImpl | ||
import ru.otus.sc.counter.dao.impl.CounterDaoImpl | ||
import ru.otus.sc.counter.service.CounterService | ||
import ru.otus.sc.counter.service.impl.CounterServiceImpl | ||
import ru.otus.sc.echo.dao.impl.EchoDaoImpl | ||
import ru.otus.sc.echo.service.EchoService | ||
import ru.otus.sc.echo.service.impl.EchoServiceImpl | ||
import ru.otus.sc.greet.dao.impl.GreetingDaoImpl | ||
import ru.otus.sc.greet.service.GreetingService | ||
import ru.otus.sc.greet.service.impl.GreetingServiceImpl | ||
import ru.otus.sc.reverse.dao.impl.ReverseDaoImpl | ||
import ru.otus.sc.reverse.service.ReverseService | ||
import ru.otus.sc.reverse.service.impl.ReverseServiceImpl | ||
import ru.otus.sc.storage.dao.impl.StorageDaoImpl | ||
import ru.otus.sc.storage.service.StorageService | ||
import ru.otus.sc.storage.service.impl.StorageServiceImpl | ||
import ru.otus.sc.sum.dao.impl.SumDaoImpl | ||
import ru.otus.sc.sum.service.SumService | ||
import ru.otus.sc.sum.service.impl.SumServiceImpl | ||
import ru.otus.sc.user.dao.impl.{UserDaoImpl, UserTagDaoImpl} | ||
import ru.otus.sc.user.model.User | ||
import ru.otus.sc.user.service.impl.{UserServiceImpl, UserTagServiceImpl} | ||
import ru.otus.sc.user.service.{UserService, UserTagService} | ||
|
||
// Helper class which aggregates service entries to single point | ||
case class Engine( | ||
countdowning: CountdownService, | ||
counting: CounterService, | ||
echoing: EchoService, | ||
getting: StorageService[StorageKey, StorageValue], | ||
greeting: GreetingService[Greeted], | ||
reversing: ReverseService, | ||
summing: SumService, | ||
usering: UserService, | ||
userTagging: UserTagService | ||
) | ||
|
||
object Engine { | ||
type StorageKey = String | ||
type StorageValue = String | ||
type Greeted = User | ||
|
||
def apply(): Engine = { | ||
val CountdownDao = new CountdownDaoImpl | ||
val countdownService = new CountdownServiceImpl(CountdownDao) | ||
val CounterDao = new CounterDaoImpl | ||
val counterService = new CounterServiceImpl(CounterDao) | ||
val echoDao = new EchoDaoImpl | ||
val echoService = new EchoServiceImpl(echoDao) | ||
val greetingDao = new GreetingDaoImpl | ||
val greetingService = new GreetingServiceImpl[Greeted](greetingDao) | ||
val storageDao = new StorageDaoImpl[StorageKey, StorageValue] | ||
val storageService = new StorageServiceImpl[StorageKey, StorageValue](storageDao) | ||
val reverseDao = new ReverseDaoImpl | ||
val reverseService = new ReverseServiceImpl(reverseDao) | ||
val sumDao = new SumDaoImpl | ||
val sumService = new SumServiceImpl(sumDao) | ||
val userDao = new UserDaoImpl | ||
val userService = new UserServiceImpl(userDao) | ||
val userTagDao = new UserTagDaoImpl | ||
val userTagService = new UserTagServiceImpl(userTagDao) | ||
|
||
Engine( | ||
countdownService, | ||
counterService, | ||
echoService, | ||
storageService, | ||
greetingService, | ||
reverseService, | ||
sumService, | ||
userService, | ||
userTagService | ||
) | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/main/scala/ru/otus/sc/countdown/dao/CountdownDao.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package ru.otus.sc.countdown.dao | ||
|
||
import ru.otus.sc.countdown.model.Countdown | ||
import ru.otus.sc.countdown.model.Countdown.{CompareValues, CountdownId, CountdownValue, UpdaterId} | ||
|
||
trait CountdownDao { | ||
def createCountdown(countdown: Countdown): Countdown | ||
def deleteCountdown(id: CountdownId): Option[Countdown] | ||
def getCountdown(id: CountdownId): Option[Countdown] | ||
def updateCountdown(countdown: Countdown): Option[Countdown] | ||
def findCountdownsByValue(value: CountdownValue, predicate: CompareValues): Seq[Countdown] | ||
def findCountdownsByUpdater(updater: UpdaterId): Seq[Countdown] | ||
def findAllDone: Seq[Countdown] | ||
def findAllNonDone: Seq[Countdown] | ||
} |
72 changes: 72 additions & 0 deletions
72
src/main/scala/ru/otus/sc/countdown/dao/impl/CountdownDaoImpl.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package ru.otus.sc.countdown.dao.impl | ||
|
||
import java.util.UUID | ||
|
||
import ru.otus.sc.countdown.dao.CountdownDao | ||
import ru.otus.sc.countdown.model.Countdown | ||
import ru.otus.sc.countdown.model.Countdown.{CompareValues, CountdownId, CountdownValue, UpdaterId} | ||
|
||
class CountdownDaoImpl extends CountdownDao { | ||
private var countdowns = Map[CountdownId, Countdown]() | ||
|
||
def createCountdown(countdown: Countdown): Countdown = { | ||
|
||
val id = UUID.randomUUID() | ||
val newCountdown = countdown match { | ||
case Countdown.Done(_) => Countdown.Done(Some(id)) | ||
case Countdown.Tick(_, updater, value) => Countdown.Tick(Some(id), updater, value) | ||
} | ||
countdowns += (id -> newCountdown) | ||
newCountdown | ||
} | ||
|
||
def deleteCountdown(id: CountdownId): Option[Countdown] = | ||
for { | ||
deletedCountdown <- countdowns.get(id) | ||
} yield { | ||
countdowns -= id | ||
deletedCountdown | ||
} | ||
|
||
def getCountdown(id: CountdownId): Option[Countdown] = countdowns.get(id) | ||
|
||
def updateCountdown(countdown: Countdown): Option[Countdown] = { | ||
// only CountdownTick can be updated | ||
val (countdownId, updaterId) = countdown match { | ||
case Countdown.Tick(id, updater, _) => (id, Some(updater)) | ||
case Countdown.Done(_) => (None, None) | ||
} | ||
|
||
for { | ||
id <- countdownId | ||
updater <- updaterId | ||
currentCountdown <- countdowns.get(id) | ||
} yield { | ||
val newCountdown = currentCountdown match { | ||
case alreadyDone @ Countdown.Done(_) => alreadyDone | ||
case Countdown.Tick(id, _, value) => | ||
val newValue = value - 1L | ||
if (newValue <= 0) Countdown.Done(id) | ||
else Countdown.Tick(id, updater, newValue) | ||
} | ||
countdowns += (id -> newCountdown) | ||
newCountdown | ||
} | ||
} | ||
|
||
def findCountdownsByValue(value: CountdownValue, predicate: CompareValues): Seq[Countdown] = | ||
countdowns.values.collect { | ||
case x @ Countdown.Tick(_, _, currentValue) if predicate(value, currentValue) => x | ||
}.toVector | ||
|
||
def findCountdownsByUpdater(updater: UpdaterId): Seq[Countdown] = | ||
countdowns.values.collect { | ||
case x @ Countdown.Tick(_, updaterId, _) if updaterId == updater => x | ||
}.toVector | ||
|
||
def findAllDone: Seq[Countdown] = | ||
countdowns.values.collect { case x @ Countdown.Done(_) => x }.toVector | ||
|
||
def findAllNonDone: Seq[Countdown] = | ||
countdowns.values.collect { case x @ Countdown.Tick(_, _, _) => x }.toVector | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Упоминал в прошлом ДЗ что лучше использовать ScalaDoc формат комментариев.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Да, я делал его до проверки прошлого ДЗ, поэтому все еще так :))