@@ -65,7 +65,7 @@ content:
65
65
[,clojure]
66
66
----
67
67
{:deps {org.clojure/clojure {:mvn/version "1.12.0"}
68
- org.duct-framework/main {:mvn/version "0.1.3 "}}
68
+ org.duct-framework/main {:mvn/version "0.1.4 "}}
69
69
:aliases {:duct {:main-opts ["-m" "duct.main"]}}}
70
70
----
71
71
@@ -241,7 +241,7 @@ We'll first add the new dependency:
241
241
[,clojure]
242
242
----
243
243
{:deps {org.clojure/clojure {:mvn/version "1.12.0"}
244
- org.duct-framework/main {:mvn/version "0.1.3 "}
244
+ org.duct-framework/main {:mvn/version "0.1.4 "}
245
245
org.duct-framework/module.logging {:mvn/version "0.6.5"}}
246
246
:aliases {:duct {:main-opts ["-m" "duct.main"]}}}
247
247
----
@@ -556,7 +556,7 @@ modules: logging and web.
556
556
[,clojure]
557
557
----
558
558
{:deps {org.clojure/clojure {:mvn/version "1.12.0"}
559
- org.duct-framework/main {:mvn/version "0.1.3 "}
559
+ org.duct-framework/main {:mvn/version "0.1.4 "}
560
560
org.duct-framework/module.logging {:mvn/version "0.6.5"}
561
561
org.duct-framework/module.web {:mvn/version "0.11.1"}}
562
562
:aliases {:duct {:main-opts ["-m" "duct.main"]}}}
@@ -772,8 +772,146 @@ Or we could return the string directly:
772
772
<html lang=\"en\">
773
773
<head><title>Hello World Wide Web</title></head>
774
774
<body><h1>Hello World Wide Web</h1></body>
775
- </html>
775
+ </html>"}))
776
776
----
777
777
778
778
All of these examples are equivalent, but returning a vector is the most
779
779
convenient and concise.
780
+
781
+ === SQL Database
782
+
783
+ The next step is to add a database to our application. We'll use
784
+ https://www.sqlite.org/index.html[SQLite], which means we need the
785
+ corresponding JDBC adapter as a dependency.
786
+
787
+ To give us a Clojure-friendly way of querying the database, we'll also
788
+ add a dependency on
789
+ https://github.com/seancorfield/next-jdbc[next.jdbc].
790
+
791
+ Finally, we'll add the Duct SQL module. This will add a connection pool
792
+ to the system that we can use to access the database.
793
+
794
+ Our project dependencies should now look like this:
795
+
796
+ .deps.edn
797
+ [,clojure]
798
+ ----
799
+ {:deps {org.clojure/clojure {:mvn/version "1.12.0"}
800
+ org.duct-framework/main {:mvn/version "0.1.4"}
801
+ org.duct-framework/module.logging {:mvn/version "0.6.5"}
802
+ org.duct-framework/module.web {:mvn/version "0.11.1"}
803
+ org.duct-framework/module.sql {:mvn/version "0.7.1"}
804
+ org.xerial/sqlite-jdbc {:mvn/version "3.47.0.0"}
805
+ com.github.seancorfield/next.jdbc {:mvn/version "1.3.955"}}
806
+ :aliases {:duct {:main-opts ["-m" "duct.main"]}}}
807
+ ----
808
+
809
+ We can load these new dependencies either by restarting the REPL, or by
810
+ using the `sync-deps` function.
811
+
812
+ [,clojure]
813
+ ----
814
+ user=> (sync-deps)
815
+ [...]
816
+ ----
817
+
818
+ The next step is to add `:duct.module/sql` to our Duct configuration.
819
+
820
+ .duct.edn
821
+ [,clojure]
822
+ ----
823
+ {:system
824
+ {:duct.module/logging {}
825
+ :duct.module/sql {}
826
+ :duct.module/web
827
+ {:features #{:site}
828
+ :routes [["/" {:get :todo.routes/index}]]}}}
829
+ ----
830
+
831
+ Then reset via the REPL:
832
+
833
+ [,shell]
834
+ ----
835
+ user=> (reset)
836
+ :reloading ()
837
+ Execution error (ExceptionInfo) at integrant.core/unbound-vars-exception (core.cljc:343).
838
+ Unbound vars: jdbc-url
839
+ ----
840
+
841
+ Wait, what's this about an unbound var? Where did that come from?
842
+
843
+ Modules can add vars, and the SQL module adds one called `jdbc-url`.
844
+ This var can be set via:
845
+
846
+ - A command-line argument, `--jdbc-url`
847
+ - An environment variable, `JDBC_DATABASE_URL`
848
+
849
+ We can also set a default value for this var via the configuration. As
850
+ SQLite uses a local file for its database, we can add a default to be
851
+ used in development.
852
+
853
+ .duct.edn
854
+ [,clojure]
855
+ ----
856
+ {:vars {jdbc-url {:default "jdbc:sqlite:todo.db"}}
857
+ :system
858
+ {:duct.module/logging {}
859
+ :duct.module/sql {}
860
+ :duct.module/web
861
+ {:features #{:site}
862
+ :routes [["/" {:get :todo.routes/index}]]}}}
863
+ ----
864
+
865
+ If we want to change this in production, we can use the corresponding
866
+ command-line argument or environment variable to override this default.
867
+
868
+ [,shell]
869
+ ----
870
+ user=> (reset)
871
+ :reloading ()
872
+ :resumed
873
+ ----
874
+
875
+ The SQL module adds a database connection, but we need to add a ref to
876
+ our route handlers in order for them to use it. We could do this
877
+ by adding a ref to each handler:
878
+
879
+ [,clojure]
880
+ ----
881
+ {:todo.routes/index {:db #ig/ref :duct.database/sql}
882
+ ----
883
+
884
+ This is useful if only some routes need to access the database. However,
885
+ in this case, we expect that all routes will need database access in
886
+ some fashion. To make this easier, the web module has an option,
887
+ `:handler-opts` that applies common options to all route handlers it
888
+ generates.
889
+
890
+ .duct.edn
891
+ [,clojure]
892
+ ----
893
+ {:vars {jdbc-url {:default "jdbc:sqlite:todo.db"}}
894
+ :system
895
+ {:duct.module/logging {}
896
+ :duct.module/sql {}
897
+ :duct.module/web
898
+ {:features #{:site}
899
+ :handler-opts {:db #ig/ref :duct.database/sql}
900
+ :routes [["/" {:get :todo.routes/index}]]}}}
901
+ ----
902
+
903
+ This will add a `javax.sql.DataSource` object to the `:db` key of the
904
+ component options. We can access this from the route handler function we
905
+ created earlier.
906
+
907
+ .src/todo/routes.clj
908
+ [,clojure]
909
+ ----
910
+ (ns todo.routes)
911
+
912
+ (defn index [{:keys [db]}]
913
+ (fn [_request]
914
+ [:html {:lang "en"}
915
+ [:head [:title "Hello World Wide Web"]]
916
+ [:body [:h1 "Hello World Wide Web"]]]))
917
+ ----
0 commit comments