Skip to content

fulcrologic/fulcro-rad-sql

Repository files navigation

SQL Database Plugin

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

fulcro rad sql

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.

Warning
Fulcrologic, LLC is not currently using this library, and no active work is being done on it. If you would like to become a maintainer on this library, please contact us.

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
           :sql/adapter        :h2 ; or :postgresql
           :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/adapter              :h2
                                            :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)}) config)]
    [automatic-resolvers
     form/resolvers
     ...]))

LICENSE

The MIT License (MIT) Copyright (c), Fulcrologic, LLC

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.