♻️ Share Ladybug connection across ingest and stats

This commit is contained in:
Alejandro Alonso 2026-07-13 13:43:03 +02:00
parent 606911ab0d
commit 275c77471d
4 changed files with 74 additions and 51 deletions

View File

@ -40,12 +40,14 @@
{:keys [statements stats]}
(project.document/projection-statements data file)
ingest-statements (conj (into ddl statements) "CHECKPOINT;")]
(ladybug/exec! db-path ingest-statements)
{:file-id file-id
:revn (:revn file)
:name (or (:name data) (:name file))
:db-path db-path
:schema-version schema/schema-version
:projection {:stats stats}
:transforms (project.transforms/apply-transforms! system db-path data file)
:stats (stats/summarize db-path)})))
(ladybug/with-connection! db-path
(fn [conn]
(ladybug/exec-on-connection! conn ingest-statements)
{:file-id file-id
:revn (:revn file)
:name (or (:name data) (:name file))
:db-path db-path
:schema-version schema/schema-version
:projection {:stats stats}
:transforms (project.transforms/apply-transforms! system db-path data file)
:stats (stats/summarize-connection conn)})))))

View File

@ -91,19 +91,7 @@
:statement statement
:err (.getErrorMessage result))))
(defn- with-connection
[db-path f]
(let [^Database db (if (memory-db-path? db-path)
(Database.)
(Database. (str db-path)))]
(try
(let [^Connection conn (Connection. db)]
(try
(f conn)
(finally
(.close conn))))
(finally
(.close db)))))
(def ^:private default-query-timeout-seconds 120)
(defn- scalar-value
[^Connection conn statement]
@ -122,36 +110,64 @@
(with-open [^QueryResult result (.query conn cypher)]
(check-success! result cypher)))))
(def ^:private default-query-timeout-seconds 120)
(defn- ensure-db-path!
[db-path]
(when-not (memory-db-path? db-path)
(fs/create-dir (fs/parent db-path))))
(defn with-connection!
"Open a Ladybug connection for `db-path` and invoke `(f conn)`.
For `:memory:`, the database only lives for the duration of this call;
all reads and writes must happen inside `f`."
[db-path f]
(ensure-db-path! db-path)
(let [^Database db (if (memory-db-path? db-path)
(Database.)
(Database. (str db-path)))]
(try
(let [^Connection conn (Connection. db)]
(try
(.setQueryTimeout conn default-query-timeout-seconds)
(f conn)
(finally
(.close conn))))
(finally
(.close db)))))
(defn exec-on-connection!
"Execute Cypher statements on an open Ladybug connection."
[^Connection conn statements]
(assert (sequential? statements) "statements should be a sequential collection")
(run-statements! conn statements))
(defn query-scalar-on-connection!
"Execute a query expected to return a single scalar value on `conn`."
[^Connection conn statement]
(scalar-value conn statement))
(defn exec!
"Execute Cypher statements against a Ladybug database.
`db-path` is either `:memory:` or a filesystem path to a `.lbug` database."
[db-path statements]
(assert (sequential? statements) "statements should be a sequential collection")
(when-not (memory-db-path? db-path)
(fs/create-dir (fs/parent db-path)))
(with-connection db-path
(fn [^Connection conn]
(.setQueryTimeout conn default-query-timeout-seconds)
(run-statements! conn statements))))
(with-connection! db-path
(fn [conn]
(exec-on-connection! conn statements))))
(defn query-scalar!
"Execute a query expected to return a single scalar value."
[db-path statement]
(with-connection db-path
(fn [^Connection conn]
(.setQueryTimeout conn default-query-timeout-seconds)
(scalar-value conn statement))))
(with-connection! db-path
(fn [conn]
(query-scalar-on-connection! conn statement))))
(defn smoke-test!
"Run a minimal CREATE + count against Ladybug."
[& {:keys [db-path] :or {db-path ":memory:"}}]
(when-not (memory-db-path? db-path)
(reset-db-path! db-path)
(fs/create-dir (fs/parent db-path)))
(with-connection db-path
(reset-db-path! db-path))
(with-connection! db-path
(fn [^Connection conn]
(run-statements! conn
["CREATE NODE TABLE Person(name STRING, age INT64, PRIMARY KEY(name));"

View File

@ -15,20 +15,25 @@
(str "`" table "`")
table))
(defn- count-query
[db-path statement]
(or (ladybug/query-scalar! db-path statement) 0))
(defn- count-on-connection
[conn statement]
(or (ladybug/query-scalar-on-connection! conn statement) 0))
(defn summarize-connection
"Return node/edge counts using an open Ladybug connection."
[conn]
{:nodes (into {}
(map (fn [{:keys [name]}]
[name (count-on-connection
conn
(str "MATCH (n:" (node-label-for-match name) ") "
"RETURN count(n) AS " name "_c;"))])
schema/node-tables))
:edges {:IsChildOf (count-on-connection
conn
"MATCH ()-[e:IsChildOf]->() RETURN count(e) AS IsChildOf_c;")}})
(defn summarize
"Return node/edge counts from the graph database."
[db-path]
{:nodes (into {}
(map (fn [{:keys [name]}]
[name (count-query
db-path
(str "MATCH (n:" (node-label-for-match name) ") "
"RETURN count(n) AS " name "_c;"))])
schema/node-tables))
:edges {:IsChildOf (count-query
db-path
"MATCH ()-[e:IsChildOf]->() RETURN count(e) AS IsChildOf_c;")}})
(ladybug/with-connection! db-path summarize-connection))

View File

@ -431,7 +431,7 @@
- `:db-path` path or `:memory:`
- `:reset-db?` delete any existing db first (default true)"
[file-id & opts]
(let [result (graph.ingest/ingest-file! main/system file-id opts)]
(let [result (apply graph.ingest/ingest-file! main/system file-id opts)]
(graph.report/print-ingest! result)
result))