Liking cljdoc? Tell your friends :D

toucan2.connection

Connection Resolution

The rules for determining which connection to use are as follows. These are tried in order until one returns non-nil:

  1. The connectable specified in the function arguments.

  2. The toucan2.connection/*current-connectable*, if bound. This is bound automatically when using with-connection or with-transaction

  3. The toucan2.model/default-connectable for the model resolved from the modelable in the function arguments;

  4. The :default implementation of toucan2.connection/do-with-connection

You can define a 'named' connectable such as ::db by adding an implementation of toucan2.connection/do-with-connection, or use things like JDBC URL connection strings or [[clojure.java.jdbc]] connection properties maps directly.

IMPORTANT CAVEAT! Positional connectables will be used in preference to *current-connectable*, even when it was bound by with-transaction -- this means your query will run OUTSIDE of the current transaction! Sometimes, this is what you want, because maybe a certain query is meant to run against a different database! Usually, however, it is not! So in that case you can either do something like

(t2/query (or conn/*current-connectable* ::my-db) ...)

to use the current connection if it exists, or define your named connectable method like

(m/defmethod conn/do-with-connection ::my-db
  [_connectable f]
  (conn/do-with-connection
   (if (and conn/*current-connectable*
            (not= conn/*current-connectable* ::my-db))
       conn/*current-connectable*
       "jdbc:postgresql://...")
   f))

This, however, is super annoying! So I might reconsider this behavior in the future.

For reducible queries, the connection is not resolved until the query is executed, so you may create a reducible query with no default connection available and execute it later with one bound. (This also means that toucan2.execute/reducible-query does not capture dynamic bindings such as toucan2.connection/*current-connectable* -- you probably wouldn't want it to, anyway, since we have no guarantees and open connection will be around when we go to use the reducible query later.)

#### Connection Resolution

The rules for determining which connection to use are as follows. These are tried in order until one returns
non-nil:

1. The connectable specified in the function arguments.

2. The [[toucan2.connection/*current-connectable*]], if bound. This is bound automatically when
   using [[with-connection]] or [[with-transaction]]

3. The [[toucan2.model/default-connectable]] for the model resolved from the `modelable` in the function arguments;

4. The `:default` implementation of [[toucan2.connection/do-with-connection]]

You can define a 'named' connectable such as `::db` by adding an implementation
of [[toucan2.connection/do-with-connection]], or use things like JDBC URL connection strings or [[clojure.java.jdbc]]
connection properties maps directly.

IMPORTANT CAVEAT! Positional connectables will be used in preference to [[*current-connectable*]], even when it was
bound by [[with-transaction]] -- this means your query will run OUTSIDE of the current transaction! Sometimes, this is
what you want, because maybe a certain query is meant to run against a different database! Usually, however, it is
not! So in that case you can either do something like

```clj
(t2/query (or conn/*current-connectable* ::my-db) ...)
```

to use the current connection if it exists, or define your named connectable method like

```clj
(m/defmethod conn/do-with-connection ::my-db
  [_connectable f]
  (conn/do-with-connection
   (if (and conn/*current-connectable*
            (not= conn/*current-connectable* ::my-db))
       conn/*current-connectable*
       "jdbc:postgresql://...")
   f))
```

This, however, is super annoying! So I might reconsider this behavior in the future.

For reducible queries, the connection is not resolved until the query is executed, so you may create a reducible query
with no default connection available and execute it later with one bound. (This also means
that [[toucan2.execute/reducible-query]] does not capture dynamic bindings such
as [[toucan2.connection/*current-connectable*]] -- you probably wouldn't want it to, anyway, since we have no
guarantees and open connection will be around when we go to use the reducible query later.)
raw docstring

toucan2.delete

Implementation of delete!.

Code for building Honey SQL for DELETE lives in toucan2.map-backend.honeysql2

Implementation of [[delete!]].

Code for building Honey SQL for DELETE lives in [[toucan2.map-backend.honeysql2]]
raw docstring

toucan2.execute

Code for executing queries and statements, and reducing their results.

The functions here meant for use on a regular basis are:

  • query -- resolve and compile a connectable, execute it using a connection from a connectable, and immediately fully realize the results.

  • query-one -- like query, but only realizes the first result.

  • reducible-query -- like query, but returns a [[clojure.lang.IReduceInit]] that can be reduced later rather than immediately realizing the results.

  • with-call-count -- helper macro to count the number of queries executed within a body.

Code for executing queries and statements, and reducing their results.

The functions here meant for use on a regular basis are:

* [[query]] -- resolve and compile a connectable, execute it using a connection from a connectable, and immediately
               fully realize the results.

* [[query-one]] -- like [[query]], but only realizes the first result.

* [[reducible-query]] -- like [[query]], but returns a [[clojure.lang.IReduceInit]] that can be reduced later rather
  than immediately realizing the results.

* [[with-call-count]] -- helper macro to count the number of queries executed within a `body`.
raw docstring

toucan2.insert

Implementation of insert!.

The code for building an INSERT query as Honey SQL lives in toucan2.map-backend.honeysql2

Implementation of [[insert!]].

The code for building an INSERT query as Honey SQL lives in [[toucan2.map-backend.honeysql2]]
raw docstring

toucan2.instance

Toucan 2 instances are a custom map type that does two things regular maps do not do:

  1. They are associated with a particular model; [[toucan2.protocols/model]] can be used to get it. This is usually set when the instance comes out of that database.

  2. They track their [[toucan2.protocols/original]] version when they come out of the application database. This can in turn be used to calculate the [[toucan2.protocols/changes]] that have been made, which powers features like toucan2.save/save!.

Normally a Toucan instance is considered equal to a plain map with the same current (via [[toucan2.protocols/current]]) value. It is considered equal to other instances if they have the same current value and their model is the same.

Toucan 2 instances are a custom map type that does two things regular maps do not do:

1. They are associated with a particular model; [[toucan2.protocols/model]] can be used to get it. This is usually set
   when the instance comes out of that database.

2. They track their [[toucan2.protocols/original]] version when they come out of the application database. This can in
   turn be used to calculate the [[toucan2.protocols/changes]] that have been made, which powers features
   like [[toucan2.save/save!]].

Normally a Toucan instance is considered equal to a plain map with the same
current (via [[toucan2.protocols/current]]) value. It is considered equal to other instances if they have the same
current value and their model is the same.
raw docstring

toucan2.jdbc

The Toucan 2 next.jdbc query execution backend.

The Toucan 2 `next.jdbc` query execution backend.
raw docstring

toucan2.jdbc.read

read-column-thunk method, which is used to determine how to read values of columns in results, and default implementations

[[read-column-thunk]] method, which is used to determine how to read values of columns in results, and default
implementations
raw docstring

toucan2.jdbc.result-set

Implementation of a custom next.jdbc result set builder function, builder-fn, and the default implementation; [[reduce-result-set]] which is used to reduce results from JDBC databases.

Implementation of a custom `next.jdbc` result set builder function, [[builder-fn]], and the default
implementation; [[reduce-result-set]] which is used to reduce results from JDBC databases.
raw docstring

toucan2.log

Toucan 2 logging utilities. This is basically just a fancy wrapper around clojure.tools.logging that supports some additional debugging facilities, such as dynamically enabling logging for different topics or levels from the REPL.

Toucan 2 logging utilities. This is basically just a fancy wrapper around `clojure.tools.logging` that supports some
additional debugging facilities, such as dynamically enabling logging for different topics or levels from the REPL.
raw docstring

toucan2.map-backend

Map query build/compilation backend.

A map backend must named by a keyword, and should implement the following methods:

Map query build/compilation backend.

A map backend must named by a keyword, and should implement the following methods:

- [[toucan2.map-backend/load-backend-if-needed]]: initialize the backend as needed and load any namespaces that may
  need to be loaded.

- [[toucan2.query/apply-kv-arg]]: Tell Toucan 2 what to do with key-value args to functions
  like [[toucan2.select/select]].

- [[toucan2.pipeline/build]]: splice in default values, and handle parsed-args as passed to various functions. You may
  want separate implementations for different query types; see [[toucan2.types]] for the query type hierarchy)

- [[toucan2.pipeline/compile]]: compile the map into a query that can be executed natively by the query execution
  backend.
raw docstring

toucan2.model

Methods related to resolving Toucan 2 models, appropriate table names to use when building queries for them, and namespaces to use for columns in query results.

Methods related to resolving Toucan 2 models, appropriate table names to use when building queries for them, and
namespaces to use for columns in query results.
raw docstring

toucan2.pipeline

This is a low-level namespace implementing our query execution pipeline. Most of the stuff you'd use on a regular basis are implemented on top of stuff here.

Pipeline order is

  1. toucan2.query/parse-args (entrypoint fn: [[transduce-unparsed]])
  2. toucan2.model/resolve-model (entrypoint fn: [[transduce-parsed]])
  3. resolve
  4. transduce-query
  5. build
  6. compile
  7. results-transform
  8. transduce-execute-with-connection

The main pipeline entrypoint is [[transduce-unparsed]].

This is a low-level namespace implementing our query execution pipeline. Most of the stuff you'd use on a regular basis
are implemented on top of stuff here.

Pipeline order is

1. [[toucan2.query/parse-args]]    (entrypoint fn: [[transduce-unparsed]])
2. [[toucan2.model/resolve-model]] (entrypoint fn: [[transduce-parsed]])
3. [[resolve]]
4. [[transduce-query]]
5. [[build]]
6. [[compile]]
7. [[results-transform]]
8. [[transduce-execute-with-connection]]

The main pipeline entrypoint is [[transduce-unparsed]].
raw docstring

toucan2.query-execution-backend.jdbc

No vars found in this namespace.

toucan2.query-execution-backend.jdbc.mysql-mariadb

MySQL and MariaDB integration (mostly workarounds for broken stuff).

MySQL and MariaDB integration (mostly workarounds for broken stuff).
raw docstring

No vars found in this namespace.

toucan2.query-execution-backend.jdbc.postgres

PostgreSQL integration.

PostgreSQL integration.
raw docstring

No vars found in this namespace.

toucan2.select

Implementation of select and variations.

The args spec used by select lives in toucan2.query, specifically :toucan2.query/default-args.

Code for building Honey SQL for a SELECT lives in toucan2.map-backend.honeysql2.

Functions that return primary keys

Functions that return primary keys such as select-pks-set determine which primary keys to return by calling toucan2.model/select-pks-fn, which is based on the model's implementation of toucan2.model/primary-keys. Models with just a single primary key column will return primary keys 'unwrapped', i.e., the values of that column will be returned directly. Models with compound primary keys (i.e., primary keys consisting of more than one column) will be returned in vectors as if by calling juxt.

;; A model with a one-column primary key, :id
(t2/select-pks-vec :models/venues :category "bar")
;; => [1 2]

;; A model with a compound primary key, [:id :name]
(t2/select-pks-vec :models/venues.compound-key :category "bar")
;; => [[1 "Tempest"] [2 "Ho's Tavern"]]
Implementation of [[select]] and variations.

The args spec used by [[select]] lives in [[toucan2.query]], specifically `:toucan2.query/default-args`.

Code for building Honey SQL for a SELECT lives in [[toucan2.map-backend.honeysql2]].

### Functions that return primary keys

Functions that return primary keys such as [[select-pks-set]] determine which primary keys to return by
calling [[toucan2.model/select-pks-fn]], which is based on the model's implementation
of [[toucan2.model/primary-keys]]. Models with just a single primary key column will return primary keys 'unwrapped',
i.e., the values of that column will be returned directly. Models with compound primary keys (i.e., primary keys
consisting of more than one column) will be returned in vectors as if by calling `juxt`.

```clj
;; A model with a one-column primary key, :id
(t2/select-pks-vec :models/venues :category "bar")
;; => [1 2]

;; A model with a compound primary key, [:id :name]
(t2/select-pks-vec :models/venues.compound-key :category "bar")
;; => [[1 "Tempest"] [2 "Ho's Tavern"]]
```
raw docstring

toucan2.tools.after

Common code shared by various after- methods. Since the after methods operate over instances, we need to upgrade result-type/pks and result-type/update-count queries to result-type/instances, run them with the 'upgraded' result type, run our after stuff on each row, and then return the original results.

Common code shared by various `after-` methods. Since the `after` methods operate over instances, we need to upgrade
`result-type/pks` and `result-type/update-count` queries to `result-type/instances`, run them with the 'upgraded'
result type, run our after stuff on each row, and then return the original results.
raw docstring

toucan2.tools.compile

Macros that can wrap a form and return the built query, compiled query, etc. without executing it.

Macros that can wrap a form and return the built query, compiled query, etc. without executing it.
raw docstring

toucan2.tools.disallow

No vars found in this namespace.

toucan2.tools.hydrate

hydrate adds one or more keys to an instance or instances using various hydration strategies, usually using one of the existing keys in those instances. A typical use case would be to take a sequence of orders and add :user keys to them based on their values of the foreign key :user-id.

hydrate is how you use the hydration facilities; everything else in this namespace is only for extending hydration to support your models.

Toucan 2 ships with several hydration strategies out of the box:

Automagic Batched Hydration (via model-for-automagic-hydration)

hydrate attempts to do a batched hydration where possible. If the key being hydrated is defined as one of some table's model-for-automagic-hydration, hydrate will do a batched toucan2.select/select if a corresponding key (by default, the same key suffixed by -id) is found in the objects being batch hydrated. The corresponding key can be customized by implementing fk-keys-for-automagic-hydration.

(hydrate [{:user_id 100}, {:user_id 101}] :user)

Since :user is a hydration key for :models/User, a single toucan2.select/select will used to fetch Users:

(db/select :models/User :id [:in #{100 101}])

The corresponding Users are then added under the key :user.

Function-Based Batched Hydration (via batched-hydrate methods)

If the key can't be hydrated auto-magically with the appropriate model-for-automagic-hydration, hydrate will attempt to do batched hydration if it can find a matching method for batched-hydrate. If a matching function is found, it is called with a collection of objects, e.g.

(m/defmethod hydrate/batched-hydrate [:default :fields]
  [_model _k instances]
  (let [id->fields (get-some-fields instances)]
    (for [instance instances]
      (assoc instance :fields (get id->fields (:id instance))))))

Simple Hydration (via simple-hydrate methods)

If the key is not eligible for batched hydration, hydrate will look for a matching simple-hydrate method. simple-hydrate is called with a single instance.

(m/defmethod simple-hydrate [:default :dashboard]
  [_model _k {:keys [dashboard-id], :as instance}]
  (assoc instance :dashboard (select/select-one :models/Dashboard :toucan/pk dashboard-id)))

Hydrating Multiple Keys

You can hydrate several keys at one time:

(hydrate {...} :a :b)
  -> {:a 1, :b 2}

Nested Hydration

You can do recursive hydration by listing keys inside a vector:

(hydrate {...} [:a :b])
  -> {:a {:b 1}}

The first key in a vector will be hydrated normally, and any subsequent keys will be hydrated inside the corresponding values for that key.

(hydrate {...}
         [:a [:b :c] :e])
  -> {:a {:b {:c 1} :e 2}}

Forcing Hydration

Normally, hydration is skipped if an instance already has a non-nil value for the key being hydrated, but you can override this behavior by implementing needs-hydration?.

Flowchart

If you're digging in to the details, this is a flowchart of how hydration works:

                    hydrate ◄─────────────┐
                       │                  │
                       ▼                  │
                 hydrate-forms            │
                       │                  │
                       ▼                  │ (recursively)
                hydrate-one-form          │
                       │                  │
            keyword? ◄─┴─► sequence?      │
               │               │          │
               ▼               ▼          │
          hydrate-key    hydrate-key-seq ─┘
               │
               ▼
      (for each strategy) ◄────────┐
       ::automagic-batched         │
       ::multimethod-batched       │
       ::multimethod-simple        │
               │                   │ (try next strategy)
               ▼                   │
      can-hydrate-with-strategy?   │
               │                   │
        yes ◄──┴──► no ────────────┘
         │
         ▼
hydrate-with-strategy
[[hydrate]] adds one or more keys to an instance or instances using various hydration strategies, usually using one of
the existing keys in those instances. A typical use case would be to take a sequence of `orders` and add `:user` keys
to them based on their values of the foreign key `:user-id`.

[[hydrate]] is how you *use* the hydration facilities; everything else in this namespace is only for extending
hydration to support your models.

Toucan 2 ships with several hydration strategies out of the box:

#### Automagic Batched Hydration (via [[model-for-automagic-hydration]])

[[hydrate]] attempts to do a *batched hydration* where possible. If the key being hydrated is defined as one of some
table's [[model-for-automagic-hydration]], `hydrate` will do a batched
[[toucan2.select/select]] if a corresponding key (by default, the same key suffixed by `-id`) is found in the
objects being batch hydrated. The corresponding key can be customized by
implementing [[fk-keys-for-automagic-hydration]].

```clj
(hydrate [{:user_id 100}, {:user_id 101}] :user)
```

Since `:user` is a hydration key for `:models/User`, a single [[toucan2.select/select]] will used to fetch Users:

```clj
(db/select :models/User :id [:in #{100 101}])
```

The corresponding Users are then added under the key `:user`.

#### Function-Based Batched Hydration (via [[batched-hydrate]] methods)

If the key can't be hydrated auto-magically with the appropriate [[model-for-automagic-hydration]],
[[hydrate]] will attempt to do batched hydration if it can find a matching method
for [[batched-hydrate]]. If a matching function is found, it is called with a collection of
objects, e.g.

```clj
(m/defmethod hydrate/batched-hydrate [:default :fields]
  [_model _k instances]
  (let [id->fields (get-some-fields instances)]
    (for [instance instances]
      (assoc instance :fields (get id->fields (:id instance))))))
```

#### Simple Hydration (via [[simple-hydrate]] methods)

If the key is *not* eligible for batched hydration, [[hydrate]] will look for a matching
[[simple-hydrate]] method. `simple-hydrate` is called with a single instance.

```clj
(m/defmethod simple-hydrate [:default :dashboard]
  [_model _k {:keys [dashboard-id], :as instance}]
  (assoc instance :dashboard (select/select-one :models/Dashboard :toucan/pk dashboard-id)))
```

#### Hydrating Multiple Keys

You can hydrate several keys at one time:

```clj
(hydrate {...} :a :b)
  -> {:a 1, :b 2}
```

#### Nested Hydration

You can do recursive hydration by listing keys inside a vector:

```clj
(hydrate {...} [:a :b])
  -> {:a {:b 1}}
```

The first key in a vector will be hydrated normally, and any subsequent keys will be hydrated *inside* the
corresponding values for that key.

```clj
(hydrate {...}
         [:a [:b :c] :e])
  -> {:a {:b {:c 1} :e 2}}
```

### Forcing Hydration

Normally, hydration is skipped if an instance already has a non-nil value for the key being hydrated, but you can
override this behavior by implementing [[needs-hydration?]].

### Flowchart

If you're digging in to the details, this is a flowchart of how hydration works:

```
                    hydrate ◄─────────────┐
                       │                  │
                       ▼                  │
                 hydrate-forms            │
                       │                  │
                       ▼                  │ (recursively)
                hydrate-one-form          │
                       │                  │
            keyword? ◄─┴─► sequence?      │
               │               │          │
               ▼               ▼          │
          hydrate-key    hydrate-key-seq ─┘
               │
               ▼
      (for each strategy) ◄────────┐
       ::automagic-batched         │
       ::multimethod-batched       │
       ::multimethod-simple        │
               │                   │ (try next strategy)
               ▼                   │
      can-hydrate-with-strategy?   │
               │                   │
        yes ◄──┴──► no ────────────┘
         │
         ▼
hydrate-with-strategy
```
raw docstring

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close