Fork me on GitHub
#beginners
<
2022-05-22
>
2FO03:05:28

I'm running into these require/next.jdbc errors when I attempt to create a postgres database: Unhandled java.io.FileNotFoundException Could not locate next/jdbc__init.class, next/jdbc.clj or next/jdbc.cljc on classpath. and the following. 1. Caused by java.lang.RuntimeException No such namespace: jdbc Here's my db setup:

(ns cljblog.db)
(require '[next.jdbc :as jdbc])

(def db
  {:dbtype "postgresql"
   :dbname "cljblog"
   :host "localhost"
   :user "postgres"
   :password "postgres"})

(def ds (jdbc/get-datasource db))

(def ds (jdbc/get-datasource db))
(def conn (jdbc/get-connection ds))

(jdbc/execute! conn ["
-- postgresql version
drop table if exists posts?;
create table posts (
  id int,
  title varchar(255),
  body text,
author varchar(25)
"])

(jdbc/execute! conn ["
insert into posts(title,body,author)
  values('Working with postgres',
'this is my first attempt at working
with postgres in Clojure', 'Sam Dees')"])

(def result-set
  (jdbc/execute!
   conn
   ["select * from posts"]))
and the project.clj
(defproject cljblog "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url ""
  :min-lein-version "2.0.0"
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [compojure "1.6.1"]
                 [ring/ring-defaults "0.3.2"]
                 [hiccup "1.0.5"]
                 [com.github.seancorfield/next.jdbc "1.2.780"]
                 [org.postgresql/postgresql "9.4-1201-jdbc41"]]
  :plugins [[lein-ring "0.12.5"]]
  :ring {:handler cljblog.handler/app}
  :repl-options {:init-ns clj-jdbc.core}
  :profiles
  {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
                        [ring/ring-mock "0.3.2"]]}})

seancorfield05:05:13

You need to share the full stacktrace so we can see where the error comes from (I see you've posted this on StackOverflow, ClojureVerse, and Slack).

seancorfield06:05:26

Your project.clj specifies clj-jdbc.core as the initial namespace and you haven't shared that (in src/clj_jdbc/core.clj) and, as on SO, I want to check you've restarted your REPL after adding com.github.seancorfield/next.jdbc as a dependency?

2FO14:05:14

Here's the full stack trace. Show: Project-Only All Hide: Clojure Java REPL Tooling Duplicates (25 frames hidden) 2. Unhandled clojure.lang.Compiler$CompilerException Error compiling src/cljblog/db.clj at (12:9) #:clojure.error{:phase :compile-syntax-check, :line 12, :column 9, :source "/home/2fo/projects/cljblog/src/cljblog/db.clj"} Compiler.java: 6808 clojure.lang.Compiler/analyze Compiler.java: 6745 clojure.lang.Compiler/analyze Compiler.java: 3820 clojure.lang.Compiler$InvokeExpr/parse Compiler.java: 7108 clojure.lang.Compiler/analyzeSeq Compiler.java: 6789 clojure.lang.Compiler/analyze Compiler.java: 38 clojure.lang.Compiler/access$300 Compiler.java: 596 clojure.lang.Compiler$DefExpr$Parser/parse Compiler.java: 7106 clojure.lang.Compiler/analyzeSeq Compiler.java: 6789 clojure.lang.Compiler/analyze Compiler.java: 6745 clojure.lang.Compiler/analyze Compiler.java: 7180 clojure.lang.Compiler/eval Compiler.java: 7131 clojure.lang.Compiler/eval core.clj: 3214 clojure.core/eval core.clj: 3210 clojure.core/eval interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn AFn.java: 152 clojure.lang.AFn/applyToHelper AFn.java: 144 clojure.lang.AFn/applyTo core.clj: 665 clojure.core/apply core.clj: 1973 clojure.core/with-bindings* core.clj: 1973 clojure.core/with-bindings* RestFn.java: 425 clojure.lang.RestFn/invoke interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn main.clj: 414 clojure.main/repl/read-eval-print/fn main.clj: 414 clojure.main/repl/read-eval-print main.clj: 435 clojure.main/repl/fn main.clj: 435 clojure.main/repl main.clj: 345 clojure.main/repl RestFn.java: 1523 clojure.lang.RestFn/invoke interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn AFn.java: 22 clojure.lang.AFn/run session.clj: 218 nrepl.middleware.session/session-exec/main-loop/fn session.clj: 217 nrepl.middleware.session/session-exec/main-loop AFn.java: 22 clojure.lang.AFn/run Thread.java: 829 java.lang.Thread/run 1. Caused by java.lang.RuntimeException No such namespace: jdbc Util.java: 221 clojure.lang.Util/runtimeException Compiler.java: 7383 clojure.lang.Compiler/resolveIn Compiler.java: 7357 clojure.lang.Compiler/resolve Compiler.java: 7318 clojure.lang.Compiler/analyzeSymbol Compiler.java: 6768 clojure.lang.Compiler/analyze Compiler.java: 6745 clojure.lang.Compiler/analyze Compiler.java: 3820 clojure.lang.Compiler$InvokeExpr/parse Compiler.java: 7108 clojure.lang.Compiler/analyzeSeq Compiler.java: 6789 clojure.lang.Compiler/analyze Compiler.java: 38 clojure.lang.Compiler/access$300 Compiler.java: 596 clojure.lang.Compiler$DefExpr$Parser/parse Compiler.java: 7106 clojure.lang.Compiler/analyzeSeq Compiler.java: 6789 clojure.lang.Compiler/analyze Compiler.java: 6745 clojure.lang.Compiler/analyze Compiler.java: 7180 clojure.lang.Compiler/eval Compiler.java: 7131 clojure.lang.Compiler/eval core.clj: 3214 clojure.core/eval core.clj: 3210 clojure.core/eval interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn AFn.java: 152 clojure.lang.AFn/applyToHelper AFn.java: 144 clojure.lang.AFn/applyTo core.clj: 665 clojure.core/apply core.clj: 1973 clojure.core/with-bindings* core.clj: 1973 clojure.core/with-bindings* RestFn.java: 425 clojure.lang.RestFn/invoke interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn main.clj: 414 clojure.main/repl/read-eval-print/fn main.clj: 414 clojure.main/repl/read-eval-print main.clj: 435 clojure.main/repl/fn main.clj: 435 clojure.main/repl main.clj: 345 clojure.main/repl RestFn.java: 1523 clojure.lang.RestFn/invoke interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn AFn.java: 22 clojure.lang.AFn/run session.clj: 218 nrepl.middleware.session/session-exec/main-loop/fn session.clj: 217 nrepl.middleware.session/session-exec/main-loop AFn.java: 22 clojure.lang.AFn/run Thread.java: 829 java.lang.Thread/run

2FO14:05:13

The :repl-options {:init-ns clj-jdbc.core}can be ignored, I haven't created that namespace (it fails with and without it). It's a cut and past job from a demo next.jdbc/postgres project . The repl was restarted after the addition of the next.jdbc dependency. I cross posted this for posterity/SEO (do let me know if that's OTT). I'll update each post with the answer.

seancorfield17:05:15

As always when debugging issues like this, I recommend trying it in a plain REPL outside your editor to eliminate interactions with other tooling. No nREPL, no CIDER. Those tools sometimes interfere with stack traces etc

2FO18:05:34

Sorry, the final part of my last message was poorly worded, it should've been "I'll update each post as and when I have the answer". I actually haven't found the solution yet.

Stef Coetzee15:05:41

How is a fullstack Clojure(Script) application structured? Suppose you use shadow-cljs for CLJS development of an SPA client and manage the overall project with Clojure CLI (deps.edn). Do you just have frontend and backend subdirectories under src? Is the backend API’s CLJ REPL started separately from the CLJS one? I don’t have a coherent way of reasoning about this yet. Pointers to resources/examples would be appreciated. Thanks!

eighttrigrams15:05:22

With a SPA, I ususally start them separately and use src/clj for backend code, src/cljs for frontend code, and src/cljc for shared code. I experimented quite a bit with different setups. Perhaps you can have a look if one of these suits you as a starting point https://github.com/eighttrigrams/cljc-protos

💡 1
Stef Coetzee15:05:53

I wondered about shared code and src/cljc seems like a great fit. Thanks for sharing. 😃 Enjoying reading through this prototypical setup in particular: https://github.com/eighttrigrams/cljc-protos/tree/main/fullstack-clj

👍 1
lassemaatta15:05:15

for an opposite opinion, see the following https://shadow-cljs.github.io/docs/UsersGuide.html#source-paths in shadow-cljs user guide: > It is not recommended to separate source files by extension (eg. src/clj, src/cljs, src/cljc). For some reason this is widely used in CLJS project templates but it just makes things harder to use.

😲 1
Stef Coetzee16:05:51

I intuitively agree with that (anti-?)recommendation for a frontend project, but less so in the case where a project consists of backend, frontend, and shared code. :thinking_face: How do you structure fullstack projects, @U0178V2SLAY?

lassemaatta16:05:44

I don't personally have strong opinions either way. At the moment I'm working with projects which follow the src/clj/`src/cljc`/`src/cljs` -convention and I do find it a bit ceremonious. A common case is "this .clj file should actually be .cljc" which requires moving it to the "other side" instead of just renaming it. Also, if you want to define macros for clojurescript (in a .clj file), where do you put it/them? If I was starting from scratch, I think I'd try to follow a couple of rules. First, separate generic infrastructure code (logging, database connection pooling, e.g. stuff you could use in another project) from your domain specific code. Second, within your domain specific code, I would group stuff by features ("here's the backend api, views and domain rules related to feature X") , not by functionality ("all backend api namespaces go in here, all frontend views go over there"). But I'm no expert nor authority on matters like this, so I make no promises that this is the best way 🙂

Stef Coetzee16:05:37

Great recommendations. I’ll definitely give that approach a try. Thanks!

👍 1
eighttrigrams12:05:13

@U0178V2SLAY I think I just followed what I thought to be the canonical way here and also suspected that the reason for doing it that way would be for reasons that the respective compilers see only "their own" stuff, because it is separated by different source-paths. It is great to hear that there is another option on the table and there are certain things that I like about it, so I'll definitely try. As for the 'where do put the macros', I just put them to the cljc folder if they were shared. Are there any differences between to cljc vs clj macros?

lassemaatta13:05:57

sure, and I don't think there's anything wrong with clj/`cljc`/`cljs` separation, lots of projects use it and it might make it easier to reason about stuff (also, some have suggested server, client, and common instead). Especially if you also have java sources in your project, it might make sense to have src/java for them to keep things nice and symmetrical. But on the other hand I don't know if anything actually requires it so it might give you more freedom to organize things semantically if you ignore the file type. I remember doing Java Spring projects, where you must organize stuff by their functionality, because you had to configure stuff by their package name (e.g. "all my web controllers are under org.company.program.app.controller -package") to make it work. I wasn't really a big fan of restrictions like that.

👍 1
lassemaatta13:05:30

fyi: https://code.thheller.com/blog/shadow-cljs/2019/10/12/clojurescript-macros.html an article highlighting some gotchas in macros, and suggests using plain clj macros for simplicity

eighttrigrams16:05:43

Yeah there are many ways to structure the codebase and it’s a bit finding some optimum for a given project. But anyway, thanks for the hints and also for the link!

Antoine Viscardi15:05:40

Hi, all! Using gen/let from test.check, I am trying to generate a vector of 0s and 1s and its inverse. The following does not work because the binding for inv-bits is not a generator.

(gen/generate
 (gen/let [bits (gen/vector (gen/choose 0 1))
           inv-bits (map #(bit-xor 1 %) bits)]
   [bits inv-bits]))
However, the following also does not work because bits in the fmap is not a generator.
(gen/generate
 (gen/let [bits (gen/vector (gen/choose 0 1))
           inv-bits (gen/fmap #(map (partial bit-xor 1) %) bits)]
   [bits inv-bits]))
Is there an idiomatic way of wrapping bits as a generator when used in subsequent bindings? I am essentially looking for a "passthrough" generator that always generates the same value, but I can't seem to find one.

lassemaatta15:05:15

gen/return perhaps?

🙌 1
Antoine Viscardi15:05:51

Yep, just found it after going through the docs for a 3rd time... Thanks a lot mate!

Antoine Viscardi15:05:00

Exactly what I was looking for

👍 1
Baye21:05:57

Hi. I am almost done with Eric Normand’s course: Beginner Clojure: An Eric Normand Signature Course. I would like to take the following courses next (also from Eric). In which order should I take them: A then B or B then A? A. ClojureScript Frontend: An Eric Normand Signature Course 1: Understanding Re-frame Learn the most popular frontend framework in ClojureScript. 2: ClojureScript Markdown Editor Build an interactive markdown editor application with live preview and bidirectional editing. • shadow-cljs • npm • Reagent • Deploy to Netlify 3: Building Re-frame Components Learn to build many interactive widgets and components in Re-frame and Reagent. We go through many examples of common GUI widgets and learn to build them ourselves B. Clojure Web Backend: An Eric Normand Signature Course 1. Web dev in Clojure 2. HTTP client: clj-http Thanks

seancorfield21:05:09

I would recommend taking B. first so you get a good understanding of HTTP request/response handling and understand how to build APIs -- because you'll want to have a backend for your frontend app to talk to as soon as you get beyond writing simple in-browser ClojureScript apps. But I may be a bit biased because I'm primarily a backend dev. You can get a lot done with just a backend, and SSR (Server-Side Rendering), and you can enhance it with stuff like HTMX and some JS to add interactivity without going full SPA (Single-Page Application).

👍 3
Baye22:05:00

I see. That makes a lot of sense. Thanks @U04V70XH6!