generated from parenthesin/microservice-boilerplate-malli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
db_docs.clj
132 lines (118 loc) · 3.96 KB
/
db_docs.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
(ns codes.clj.docs.backend.components.db-docs
(:require [clojure.java.io :as io]
[com.stuartsierra.component :as component]
[datalevin.core :as d]
[datalevin.util :as util]
[malli.core :as m]
[parenthesin.components.http.clj-http :as http]
[parenthesin.helpers.logs :as logs])
(:import [java.io File]
[java.nio.file Files]
[java.nio.file.attribute FileAttribute]))
(def GenericComponent
(m/-simple-schema
{:type :generic-component
:pred #(satisfies? component/Lifecycle %)
:type-properties {:error/message "should satisfy com.stuartsierra.component/Lifecycle protocol."}}))
(defn ^:private get-db-download-url
{:malli/schema [:=> [:cat GenericComponent] :string]}
[config]
(let [{:keys [url version file-name]} (-> config :config :db-docs)]
(format "%s/%s/%s" url version file-name)))
(defn ^:private download-input-stream!
{:malli/schema [:=> [:cat :string GenericComponent] bytes?]}
[url http]
(-> http
(http/request {:url url
:method :get
:as :byte-array})
:body
io/input-stream))
(defn ^:private unzip-stream!
{:malli/schema [:=> [:cat bytes? :string] :nil]}
[input-stream dir]
(let [stream (java.util.zip.ZipInputStream. input-stream)]
(loop [file-data (.getNextEntry stream)]
(when file-data
(let [file-path (str dir File/separatorChar (.getName file-data))
saveFile (io/file file-path)]
(if (.isDirectory file-data)
(when-not (.exists saveFile)
(.mkdirs saveFile))
(let [parentDir (io/file (.substring file-path 0 (.lastIndexOf file-path (int File/separatorChar))))]
(when-not (.exists parentDir)
(.mkdirs parentDir))
(io/copy stream saveFile))))
(recur (.getNextEntry stream))))))
(defn download-db!
{:malli/schema [:=> [:cat :string GenericComponent GenericComponent] :nil]}
[db-path config http]
(-> config
get-db-download-url
(download-input-stream! http)
(unzip-stream! db-path)))
(defprotocol DbDocsProvider
(db [component]
"Returns a database snapshot")
(conn [component]
"Returns a database connection"))
(defrecord DbDocs [schema opts config http conn]
component/Lifecycle
(start [this]
(logs/log :info :datalevin :start)
(let [{:keys [dir version]} (-> config :config :db-docs)
db-path (str dir File/separatorChar version)]
(when-not (util/file-exists db-path)
(logs/log :info :datalevin :db-not-found :downloading :start)
(download-db! db-path config http)
(logs/log :info :datalevin :db-not-found :downloading :end))
(if conn
this
(assoc this :conn (d/get-conn db-path schema opts)))))
(stop [this]
(logs/log :info :datalevin :stop)
(if conn
(do
(d/close conn)
(assoc this :conn nil))
this))
DbDocsProvider
(db [this]
(d/db (:conn this)))
(conn [this]
(:conn this)))
(defn new-db-docs
([schema opts]
(map->DbDocs {:schema schema :opts opts}))
([schema]
(map->DbDocs {:schema schema :opts nil})))
(defrecord DbDocsMock [schema opts conn db-path]
component/Lifecycle
(start [this]
(logs/log :info :datalevin :start)
(let [db-path (str (Files/createTempDirectory
"db-docs"
(into-array FileAttribute [])))]
(if conn
this
(assoc this
:conn (d/get-conn db-path schema opts)
:db-path db-path))))
(stop [this]
(logs/log :info :datalevin :stop)
(if conn
(do
(d/close conn)
(util/delete-files db-path)
(assoc this :conn nil))
this))
DbDocsProvider
(db [this]
(d/db (:conn this)))
(conn [this]
(:conn this)))
(defn new-db-docs-mock
([schema opts]
(map->DbDocsMock {:schema schema :opts opts}))
([schema]
(map->DbDocsMock {:schema schema :opts nil})))