From 96d47ae3bdcf2de295cf123f9d5471f06c88404f Mon Sep 17 00:00:00 2001 From: goat-fish <90009472+goat-duck@users.noreply.github.com> Date: Fri, 3 Sep 2021 00:30:59 +0200 Subject: [PATCH 1/3] Set up Deduplicator module --- .gitignore | 1 + README.md | 7 +++++++ elm.json | 28 ++++++++++++++++++++++++++++ src/Deduplicator.elm | 4 ++++ tests/DeduplicatorTest.elm | 27 +++++++++++++++++++++++++++ 5 files changed, 67 insertions(+) create mode 100644 .gitignore create mode 100644 elm.json create mode 100644 src/Deduplicator.elm create mode 100644 tests/DeduplicatorTest.elm diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4bc8535 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +elm-stuff diff --git a/README.md b/README.md index e70026e..5e33106 100644 --- a/README.md +++ b/README.md @@ -80,3 +80,10 @@ We want to see: ## Submitting your solution Please submit your solution as a PR including some nice commits for challenge 1 and the rest in Markdown. + +# Answers - Suzanne Wood + +# 1. Deduplicate + +To run tests: +npx elm-test diff --git a/elm.json b/elm.json new file mode 100644 index 0000000..7468f5e --- /dev/null +++ b/elm.json @@ -0,0 +1,28 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0" + }, + "indirect": { + "elm/json": "1.1.3", + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.2" + } + }, + "test-dependencies": { + "direct": { + "elm-explorations/test": "1.2.2" + }, + "indirect": { + "elm/random": "1.0.0" + } + } +} diff --git a/src/Deduplicator.elm b/src/Deduplicator.elm new file mode 100644 index 0000000..cfe53d9 --- /dev/null +++ b/src/Deduplicator.elm @@ -0,0 +1,4 @@ +module Deduplicator exposing (..) + +deduplicate : List String -> List String +deduplicate words = words diff --git a/tests/DeduplicatorTest.elm b/tests/DeduplicatorTest.elm new file mode 100644 index 0000000..343e54e --- /dev/null +++ b/tests/DeduplicatorTest.elm @@ -0,0 +1,27 @@ +module DeduplicatorTest exposing (..) + +import Deduplicator +import Expect exposing (Expectation) +import Fuzz exposing (Fuzzer, int, list, string) +import Test exposing (..) + +suite : Test +suite = + describe "The Deduplicator module" + [ describe "Deduplicator.deduplicate" -- Nest as many descriptions as you like. + [ test "returns an identical list for an list of length 1" <| + \_ -> + let + words = + ["fish"] + in + Expect.equal words (Deduplicator.deduplicate words) + , test "returns an identical list for an list of length 0" <| + \_ -> + let + words = + [] + in + Expect.equal words (Deduplicator.deduplicate words) + ] + ] From d1aa6d483d6d7f8fe3e8bb52da09c077db4207da Mon Sep 17 00:00:00 2001 From: goat-fish <90009472+goat-duck@users.noreply.github.com> Date: Fri, 3 Sep 2021 01:29:34 +0200 Subject: [PATCH 2/3] Make the deduplicator deduplicate --- src/Deduplicator.elm | 15 +++++++++++++-- tests/DeduplicatorTest.elm | 20 ++++++++++++++------ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/Deduplicator.elm b/src/Deduplicator.elm index cfe53d9..100375a 100644 --- a/src/Deduplicator.elm +++ b/src/Deduplicator.elm @@ -1,4 +1,15 @@ -module Deduplicator exposing (..) +module Deduplicator exposing (deduplicate) + deduplicate : List String -> List String -deduplicate words = words +deduplicate words = + List.foldl addToListIfNotMatch [] (List.sort words) + +addToListIfNotMatch : String -> List String -> List String +addToListIfNotMatch element partialList = + if Just element /= List.head partialList then + element :: partialList + + else + partialList + diff --git a/tests/DeduplicatorTest.elm b/tests/DeduplicatorTest.elm index 343e54e..75cb247 100644 --- a/tests/DeduplicatorTest.elm +++ b/tests/DeduplicatorTest.elm @@ -1,27 +1,35 @@ module DeduplicatorTest exposing (..) import Deduplicator -import Expect exposing (Expectation) -import Fuzz exposing (Fuzzer, int, list, string) +import Expect import Test exposing (..) + suite : Test suite = describe "The Deduplicator module" - [ describe "Deduplicator.deduplicate" -- Nest as many descriptions as you like. + [ describe "Deduplicator.deduplicate" + -- Nest as many descriptions as you like. [ test "returns an identical list for an list of length 1" <| \_ -> let words = - ["fish"] + [ "fish" ] in - Expect.equal words (Deduplicator.deduplicate words) + Expect.equal words (Deduplicator.deduplicate words) , test "returns an identical list for an list of length 0" <| \_ -> let words = [] in - Expect.equal words (Deduplicator.deduplicate words) + Expect.equal words (Deduplicator.deduplicate words) + , test "returns a deduplicated list" <| + \_ -> + let + words = + [ "fish", "chip", "egg", "fish", "egg" ] + in + Expect.equal [ "fish", "egg", "chip" ] (Deduplicator.deduplicate words) ] ] From f97e259b1084dd6e7c01dc213096390cf4d17f20 Mon Sep 17 00:00:00 2001 From: goat-duck <90009472+goat-duck@users.noreply.github.com> Date: Fri, 3 Sep 2021 01:34:45 +0200 Subject: [PATCH 3/3] Update README.md --- README.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e33106..0f62f83 100644 --- a/README.md +++ b/README.md @@ -86,4 +86,80 @@ Please submit your solution as a PR including some nice commits for challenge 1 # 1. Deduplicate To run tests: -npx elm-test +`npx elm-test` + +# 2. Cars + +Schema for tables: + + CREATE TABLE `car` ( + `id` int not null PRIMARY KEY, + `lender_id` int not null + ); + CREATE TABLE `car_availability` ( + `id` int not null PRIMARY KEY, + `car_id` int not null, + `from` datetime not null, + `to` datetime not null + ); + CREATE TABLE `user` ( + `id` int not null PRIMARY KEY + ); + CREATE TABLE `user_bookings` ( + `id` int not null PRIMARY KEY, + `user_id` int not null, + `car_id` int not null, + `from` datetime not null, + `to` datetime not null + ); + +I would also add indices depending on what common queries are needed. + + + + +Relations: +- each card belongs to a lender, a lender can lend multiple cars +- car availability has slots which do not touch or overlap (these can be combined if they come up when adding) +- no two user bookings for the same car_id can overlap + +Query for finding available cars for a timeslot 'from', 'to' (pseudocode) + + select c.id as car_id, count(ub.id where ub.id is not null) as overlapping_bookings + from cars c join + car_availability ca on c.id = ca.car_id join + user_bookings ub on ( + ub.id = ca.user_id and + !((ub.from <= {from} and ub.to <= {to}) or + (ub.from >= {from} and ub.to >= {to})) # excluding non-overlapping slots + ) + where + ca.from <= {from} and ca.to >= {to} + group by c.id + having count(ub.id) = 0 + +Comparison with other solutions: +You could simplify the approach using discrete timeslots whether by hour, by day etc - but the one I outlined allows high flexibility of timeslots. I also considered storing available timeslots with bookings subtracted, already showing a complete availability picture but it becomes messy to manage, makes more sense to keep availability and bookings seperate and then layer them up when querying + + + +# 3. Frontops + +I would use a docker file with two FROM statements e.g. + + FROM xxxx as staging + WORKDIR xxx + RUN xxx + COPY xxx + RUN xxx + + FROM xxxx as production + WORKDIR xxx + RUN xxx + COPY --from=staging + RUN xxx + +This also enables deploying just staging by e.g. running `docker build --target staging ` +I would have config files with ENV variables for each environment so when running for a different FQDN in eg staging I would change in the staging config file + +For a change in API, it depends how the API change is rolled out. For example, if it was via a new FQDN I'd change that and any code changes needed for staging only and once tested move to production. If the API change is known to be sudden with no way to roll over, if possible I'd make the code be able to handle both versions for the transition.