feat: jolt-side java.sql interop + defn/defmacro meta & arity-clause fixes
For the migratus next.jdbc shim (jolt-0z5):
- core.janet: __jdbc-wrap-conn / __jdbc-conn-raw / __jdbc-make-stmt builtins.
A connection is a tagged wrapper over a jdbc.core conn carrying a clj :exec
callback so the host Statement.executeBatch runs SQL without a janet->clj call.
- javatime.janet: tagged-methods for :jolt/jdbc-conn (setAutoCommit/isClosed/
close/getMetaData), :jolt/jdbc-meta (getDatabaseProductName), :jolt/jdbc-stmt
(addBatch/executeBatch/close); java.sql.Timestamp ctor -> millis.
- evaluator.janet: instance? case for Connection/java.sql.Connection so
migratus's do-commands runs SQL through its Connection branch.
Two defn/defmacro fixes found loading migratus.core (both rooted in the reader
representing ^{:map} name metadata as a with-meta form, jolt-8w2):
- defmacro special form: unwrap a with-meta name (mirrors def), and handle the
arity-clause form (defmacro name ([params] body...)) like fn/defn — a params
vector reads as a tuple, an arity clause as a list (array).
- defn overlay: pass the bare (unwrapped) name to fn while def keeps the meta.
Conformance 335/335 x3 modes.
This commit is contained in:
parent
e2d33df484
commit
19505a5944
4 changed files with 78 additions and 6 deletions
|
|
@ -341,10 +341,14 @@
|
|||
(defmacro defn [fn-name & body]
|
||||
(let [body (if (and (seq body) (string? (first body))) (rest body) body)
|
||||
body (if (and (seq body) (map? (first body)) (not (symbol? (first body))))
|
||||
(rest body) body)]
|
||||
(rest body) body)
|
||||
;; ^{:map} metadata on the name reads as a (with-meta sym …) form, not an
|
||||
;; annotated symbol (jolt-8w2). def attaches the metadata, but fn needs a
|
||||
;; bare symbol, so unwrap it for the fn name.
|
||||
fn-only-name (if (symbol? fn-name) fn-name (first (rest fn-name)))]
|
||||
;; pass the name through to fn: the compiled fn's janet name carries it,
|
||||
;; so stack traces read app.deep/level3 instead of a gensym (jolt-2o7.1)
|
||||
`(def ~fn-name (fn ~fn-name ~@body))))
|
||||
`(def ~fn-name (fn ~fn-only-name ~@body))))
|
||||
|
||||
;; Jolt doesn't enforce privacy, so defn- is just defn (matching how Clojure's own
|
||||
;; defn- delegates to defn with :private metadata).
|
||||
|
|
|
|||
|
|
@ -1724,6 +1724,26 @@
|
|||
# the __write / __pr-str1 host seams; str-render-one stays for core-str.
|
||||
(defn core-write [s] (prin s) nil)
|
||||
|
||||
(defn core-eprint [s] (eprint s) nil)
|
||||
(defn core-eprintf [fmt & args] (eprintf fmt ;args) nil)
|
||||
|
||||
# next.jdbc host shims (the db library's next.jdbc compat layer builds on these).
|
||||
# A connection is a tagged table wrapping a jdbc.core conn (:raw) plus clj
|
||||
# callbacks: :exec runs one SQL string in the transaction (so the janet-side
|
||||
# Statement.executeBatch can run SQL without a janet->clj call), :close closes
|
||||
# the underlying conn, :product is the JDBC database product name. instance?
|
||||
# Connection (evaluator) and the :jolt/jdbc-conn tagged methods (javatime) key
|
||||
# off this shape.
|
||||
(defn core-jdbc-wrap-conn [raw exec closef product]
|
||||
@{:jolt/type :jolt/jdbc-conn :raw raw :exec exec :close closef
|
||||
:product product :closed @[false]})
|
||||
# Robust unwrap: a wrapped conn -> its :raw; anything else passes through (so the
|
||||
# next.jdbc fns accept either a wrapped conn or a bare jdbc.core conn/spec).
|
||||
(defn core-jdbc-conn-raw [x]
|
||||
(if (and (table? x) (= :jolt/jdbc-conn (get x :jolt/type))) (get x :raw) x))
|
||||
(defn core-jdbc-make-stmt [w]
|
||||
@{:jolt/type :jolt/jdbc-stmt :exec (get w :exec) :cmds @[]})
|
||||
|
||||
# newline lives in the Clojure collection tier (core/20-coll.clj).
|
||||
|
||||
# Clojure 1.11 string->scalar parsers: nil on malformed input, throw on a
|
||||
|
|
@ -2706,6 +2726,11 @@
|
|||
"hash-unordered-coll" core-hash-unordered-coll
|
||||
"gensym" gensym
|
||||
"__write" core-write
|
||||
"__eprint" core-eprint
|
||||
"__eprintf" core-eprintf
|
||||
"__jdbc-wrap-conn" core-jdbc-wrap-conn
|
||||
"__jdbc-conn-raw" core-jdbc-conn-raw
|
||||
"__jdbc-make-stmt" core-jdbc-make-stmt
|
||||
"__pr-str1" core-pr-str1
|
||||
"__make-uuid" make-uuid
|
||||
"compare" core-compare
|
||||
|
|
|
|||
|
|
@ -1583,6 +1583,11 @@
|
|||
"DateTimeFormatter" (and (table? val) (= :jolt/dt-formatter (get val :jolt/type)))
|
||||
"URL" (and (table? val) (= :jolt/url (get val :jolt/type)))
|
||||
"java.net.URL" (and (table? val) (= :jolt/url (get val :jolt/type)))
|
||||
# next.jdbc host shim: a wrapped jdbc.core connection (core.janet).
|
||||
# migratus's do-commands only runs SQL through its (instance? Connection)
|
||||
# branch, so the wrapped conn must answer true here.
|
||||
"Connection" (and (table? val) (= :jolt/jdbc-conn (get val :jolt/type)))
|
||||
"java.sql.Connection" (and (table? val) (= :jolt/jdbc-conn (get val :jolt/type)))
|
||||
# JVM char[] class — (Class/forName "[C"); jolt char arrays are Janet
|
||||
# arrays of char structs
|
||||
"[C" (and (array? val)
|
||||
|
|
@ -1793,12 +1798,23 @@
|
|||
(put v :dynamic true))
|
||||
# def returns the var (Clojure semantics); REPL prints #'ns/name
|
||||
v)))
|
||||
"defmacro" (let [name-sym (in form 1)
|
||||
"defmacro" (let [# ^{:map} metadata on the name reads as a (with-meta sym …)
|
||||
# form (jolt-8w2); unwrap to the bare symbol like def does.
|
||||
name-sym (unwrap-meta-name (in form 1))
|
||||
rest-form (tuple/slice form 2)
|
||||
# optional docstring
|
||||
has-doc? (and (> (length rest-form) 0) (string? (first rest-form)))
|
||||
args-form (if has-doc? (in rest-form 1) (first rest-form))
|
||||
body (tuple/slice rest-form (if has-doc? 2 1))
|
||||
raw-args (if has-doc? (in rest-form 1) (first rest-form))
|
||||
raw-body (tuple/slice rest-form (if has-doc? 2 1))
|
||||
# arity-clause form: (defmacro name ([params] body...)) — like
|
||||
# fn/defn. In a code form a vector literal is a tuple and a list
|
||||
# is an array, so a params vector reads as a tuple while an arity
|
||||
# clause reads as a list (array): unwrap its params + body. Single
|
||||
# arity only (what real macros use); a multi-arity macro takes the
|
||||
# first clause.
|
||||
arity-clause? (array? raw-args)
|
||||
args-form (if arity-clause? (first raw-args) raw-args)
|
||||
body (if arity-clause? (tuple/slice raw-args 1) raw-body)
|
||||
param-info (parse-params args-form)
|
||||
fixed-pats (param-info :fixed)
|
||||
rest-pat (param-info :rest)
|
||||
|
|
|
|||
|
|
@ -536,7 +536,34 @@
|
|||
# Thread stub: getContextClassLoader returns a stub so migratus jar/create code
|
||||
# that walks Thread/currentThread doesn't crash.
|
||||
(register-tagged-methods! :jolt/thread
|
||||
@{"getContextClassLoader" (fn [self] @{:jolt/type :jolt/classloader})}))
|
||||
@{"getContextClassLoader" (fn [self] @{:jolt/type :jolt/classloader})})
|
||||
# next.jdbc host shims (paired with the __jdbc-* builtins in core.janet and the
|
||||
# instance? Connection case in evaluator.janet). The wrapped connection carries
|
||||
# a clj :exec callback (run one SQL string) and a :close callback.
|
||||
# java.sql.Timestamp: migratus builds (Timestamp. millis) for the applied
|
||||
# column; represent it as the millis number so it stores and sorts directly.
|
||||
(each nm ["Timestamp" "java.sql.Timestamp"]
|
||||
(register-class-ctor! nm (fn [ms] ms)))
|
||||
(register-tagged-methods! :jolt/jdbc-conn
|
||||
@{"setAutoCommit" (fn [self _] self)
|
||||
"isClosed" (fn [self] (get (get self :closed) 0))
|
||||
"close" (fn [self]
|
||||
(unless (get (get self :closed) 0)
|
||||
((get self :close))
|
||||
(put (get self :closed) 0 true))
|
||||
nil)
|
||||
"getMetaData" (fn [self] @{:jolt/type :jolt/jdbc-meta :product (get self :product)})})
|
||||
(register-tagged-methods! :jolt/jdbc-meta
|
||||
@{"getDatabaseProductName" (fn [self] (get self :product))})
|
||||
# Statement batch: addBatch accumulates SQL strings, executeBatch runs each via
|
||||
# the connection's clj :exec callback (which executes inside the transaction).
|
||||
(register-tagged-methods! :jolt/jdbc-stmt
|
||||
@{"addBatch" (fn [self sql] (array/push (get self :cmds) sql) nil)
|
||||
"executeBatch" (fn [self]
|
||||
(def out @[])
|
||||
(each c (get self :cmds) (array/push out ((get self :exec) c)))
|
||||
out)
|
||||
"close" (fn [self] nil)}))
|
||||
|
||||
(install!)
|
||||
(install-io!)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue