♻️ Share Ladybug connection across ingest and stats

This commit is contained in:
Alejandro Alonso 2026-07-13 13:43:03 +02:00 committed by Álvaro Tejero Cantero
parent 56e741ef71
commit 833cf915fe
No known key found for this signature in database
4 changed files with 74 additions and 51 deletions

View File

@ -40,12 +40,14 @@
{:keys [statements stats]} {:keys [statements stats]}
(project.document/projection-statements data file) (project.document/projection-statements data file)
ingest-statements (conj (into ddl statements) "CHECKPOINT;")] ingest-statements (conj (into ddl statements) "CHECKPOINT;")]
(ladybug/exec! db-path ingest-statements) (ladybug/with-connection! db-path
{:file-id file-id (fn [conn]
:revn (:revn file) (ladybug/exec-on-connection! conn ingest-statements)
:name (or (:name data) (:name file)) {:file-id file-id
:db-path db-path :revn (:revn file)
:schema-version schema/schema-version :name (or (:name data) (:name file))
:projection {:stats stats} :db-path db-path
:transforms (project.transforms/apply-transforms! system db-path data file) :schema-version schema/schema-version
:stats (stats/summarize db-path)}))) :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 :statement statement
:err (.getErrorMessage result)))) :err (.getErrorMessage result))))
(defn- with-connection (def ^:private default-query-timeout-seconds 120)
[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)))))
(defn- scalar-value (defn- scalar-value
[^Connection conn statement] [^Connection conn statement]
@ -122,36 +110,64 @@
(with-open [^QueryResult result (.query conn cypher)] (with-open [^QueryResult result (.query conn cypher)]
(check-success! result 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! (defn exec!
"Execute Cypher statements against a Ladybug database. "Execute Cypher statements against a Ladybug database.
`db-path` is either `:memory:` or a filesystem path to a `.lbug` database." `db-path` is either `:memory:` or a filesystem path to a `.lbug` database."
[db-path statements] [db-path statements]
(assert (sequential? statements) "statements should be a sequential collection") (with-connection! db-path
(when-not (memory-db-path? db-path) (fn [conn]
(fs/create-dir (fs/parent db-path))) (exec-on-connection! conn statements))))
(with-connection db-path
(fn [^Connection conn]
(.setQueryTimeout conn default-query-timeout-seconds)
(run-statements! conn statements))))
(defn query-scalar! (defn query-scalar!
"Execute a query expected to return a single scalar value." "Execute a query expected to return a single scalar value."
[db-path statement] [db-path statement]
(with-connection db-path (with-connection! db-path
(fn [^Connection conn] (fn [conn]
(.setQueryTimeout conn default-query-timeout-seconds) (query-scalar-on-connection! conn statement))))
(scalar-value conn statement))))
(defn smoke-test! (defn smoke-test!
"Run a minimal CREATE + count against Ladybug." "Run a minimal CREATE + count against Ladybug."
[& {:keys [db-path] :or {db-path ":memory:"}}] [& {:keys [db-path] :or {db-path ":memory:"}}]
(when-not (memory-db-path? db-path) (when-not (memory-db-path? db-path)
(reset-db-path! db-path) (reset-db-path! db-path))
(fs/create-dir (fs/parent db-path))) (with-connection! db-path
(with-connection db-path
(fn [^Connection conn] (fn [^Connection conn]
(run-statements! conn (run-statements! conn
["CREATE NODE TABLE Person(name STRING, age INT64, PRIMARY KEY(name));" ["CREATE NODE TABLE Person(name STRING, age INT64, PRIMARY KEY(name));"

View File

@ -15,20 +15,25 @@
(str "`" table "`") (str "`" table "`")
table)) table))
(defn- count-query (defn- count-on-connection
[db-path statement] [conn statement]
(or (ladybug/query-scalar! db-path statement) 0)) (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 (defn summarize
"Return node/edge counts from the graph database." "Return node/edge counts from the graph database."
[db-path] [db-path]
{:nodes (into {} (ladybug/with-connection! db-path summarize-connection))
(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;")}})

View File

@ -431,7 +431,7 @@
- `:db-path` path or `:memory:` - `:db-path` path or `:memory:`
- `:reset-db?` delete any existing db first (default true)" - `:reset-db?` delete any existing db first (default true)"
[file-id & opts] [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) (graph.report/print-ingest! result)
result)) result))