Liking cljdoc? Tell your friends :D

SQL Database Plugin

A plugin for using SQL databases with Fulcro RAD (ALPHA)

fulcro rad sql

Current SNAPSHOT CI status: CircleCI

Current RELEASE CI status: CircleCI

See the current version of fulcro-rad-demo for a working demo. This README is possibly out of date until this gets out of ALPHA.

Configuration

In order to use the SQL plugin you must use Fulcro config support and include configuration for data pools. You may also optionally turn on schema management/generation.

The general layout of a config (which commonly includes config/defaults.edn on your classpath) should include:

...
 :com.fulcrologic.rad.database-adapters.sql/databases
   {:main {:sql/schema         :production
           :hikaricp/config    {... see below ...}}}
...

The primary keys in the databases section are database names. You may have any number of databases in your application. Each database uses a schema name, which defines which attributes in your model belong in that database.

This allows you to do things like create more than one database with the same schema and shard users across them.

Database Connection Pools

This library includes a wrapper for HikariCP connection pools. Basically all you need is a map from database name to a data source (which is what the adapter includes via HikariCP).

(ns com.example.components.connection-pools
  (:require
    [mount.core :refer [defstate]]
    [com.example.model :refer [all-attributes]]
    [com.example.components.config :refer [config]]
    [com.fulcrologic.rad.database-adapters.sql.result-set :as rs]
    [com.fulcrologic.rad.database-adapters.sql.connection :as pools]))

(defstate connection-pools
  :start
  (do
    (rs/coerce-result-sets!)
    (pools/create-connection-pools! config all-attributes))
  :stop
  (pools/stop-connection-pools! connection-pools))

We recommend you use Fulcro’s config support. The configuration options for the SQL adapter look like this:

 :com.fulcrologic.rad.database-adapters.sql/databases
                                    {:main {:flyway/migrate?          false
                                            :flyway/migrations        ["classpath:config/sql_migrations"]
                                            :hikaricp/config          {"dataSourceClassName" "org.h2.jdbcx.JdbcDataSource"
                                                                       "dataSource.user"     "sa"
                                                                       "dataSource.password" "sa"
                                                                       "dataSource.URL"      "jdbc:h2:mem:dev-db"}
                                            :sql/auto-create-missing? true
                                            :sql/schema               :production}}

Schema Generation

Automatic schema is quite nice for early development work, and is enabled with the auto-create-missing flag.

Each database should be given an (invented) schema name, which will match the schema you set on (some or all) attributes.

The automatic schema generation just tries to generate columns in tables if (and only if) they do not already exist. This is reasonable for really fast startup of a project, but is almost certainly insufficient for real projects.

As such this plugin includes functions that can leverage Flyway to execute migrations.

Using Flyway

The flyway options turn on/off (and locate) migration files. Use that if you want to manually create schema via Flyway files.

See the Flyway documentation for specific details, but the bases are as follows:

  1. Create migrations with names like Vx.y.z__description.sql in config/sql_migrations (on the CLASSPATH).

  2. Include the following in your application configuration:

...
 :com.fulcrologic.rad.database-adapters.sql/databases
   {:main {:flyway/migrate?          true
           :flyway/migrations        ["classpath:config/sql_migrations"]
           ...}}
...

Attributes

RAD attributes that will be used in an SQL database can be configured as follows (where the sql namespace is com.fulcrologic.rad.database-adapters.sql):

::attr/schema

(required) A keyword that matches the schema you want to store the attribute on.

::attr/identities

(required on non-identity attributes) A set of keyword (names) of the id attributes that identify tables for which this attribute is a row.

::sql/column-name

(optional) A string to use to override the automatic column name.

::sql/table-name

(optional, but only on identity attributes) A string. Overrides the table name that goes with a given identity attribute.

Resolvers and Save/Load Middleware

The library supports generation of batched resolvers that can run correct queries against tables that can be installed into your Pathom parser.

There is also save middleware that can automate saves on attributes that match the schema as the SQL adapter understands it. You may need additional middleware if your schema is more advanced.

The minimal middleware looks like this:

(ns com.example.components.save-middleware
(:require
  [com.fulcrologic.rad.middleware.save-middleware :as r.s.middleware]
  [com.fulcrologic.rad.database-adapters.sql.middleware :as sql-middleware]
  [com.example.model :as model]))

(def middleware
  (->
    (sql-middleware/wrap-sql-save)
    ...)))
(ns com.example.components.delete-middleware
  (:require
    [com.fulcrologic.rad.database-adapters.sql.middleware :as sql-middleware]))

(def middleware (sql-middleware/wrap-sql-delete))
(ns com.example.components.auto-resolvers
  (:require
    [com.example.model :refer [all-attributes]]
    [mount.core :refer [defstate]]
    [com.fulcrologic.rad.resolvers :as res]
    [com.fulcrologic.rad.database-adapters.sql.resolvers :as sql-res]
    [taoensso.timbre :as log]))

(defstate automatic-resolvers
  :start
  (vec
    (concat
      ;; custom resolvers that are declared on attributes
      (res/generate-resolvers all-attributes)
      ;; SQL resolvers
      (sql-res/generate-resolvers all-attributes :production))))

If you have more than one schema, simply call sq-res/generate-resolvers once for each schema. It returns a sequence of resolvers that can be installed into your parser.

The Parser

The central element of the entire back-end is the Pathom Parser. Give the above definitions it will look something like this:

(ns com.example.components.parser
  (:require
    [com.example.components.auto-resolvers :refer [automatic-resolvers]]
    [com.example.components.config :refer [config]]
    [com.example.components.connection-pools :as pools]
    [com.fulcrologic.rad.database-adapters.sql.plugin :as sql]
    [com.fulcrologic.rad.pathom :as pathom]
    [com.fulcrologic.rad.form :as form]
    [com.fulcrologic.rad.blob :as blob]
    [com.example.components.blob-store :as bs]
    [com.example.components.save-middleware :as save]
    [com.example.components.delete-middleware :as delete]
    [mount.core :refer [defstate]]
    [com.example.model :refer [all-attributes]]
    [com.example.model.account :as account]
    [com.example.model.timezone :as timezone]
    [com.fulcrologic.rad.attributes :as rad.attr]
    [com.example.model.invoice :as invoice]))

(defstate parser
  :start
  (pathom/new-parser config
    [(rad.attr/pathom-plugin all-attributes)
     (form/pathom-plugin save/middleware delete/middleware)
     (sql/pathom-plugin (fn [_] {:production (:main pools/connection-pools)}))]
    [automatic-resolvers
     form/resolvers
     ...]))

Can you improve this documentation? These fine people already did:
Tony Kay & Yann Vanhalewyn
Edit on GitHub

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

× close