Claude Code Plugins

Community-maintained marketplace

Feedback

Guide for the RAD (Rapid Application Development) model including defattr, entity definitions, identities, and test builder patterns. Use when working with the data model, creating entities, or understanding database schema.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name rad-model
description Guide for the RAD (Rapid Application Development) model including defattr, entity definitions, identities, and test builder patterns. Use when working with the data model, creating entities, or understanding database schema.

RAD Model

See also @ai/clojure-library-source-and-documentation.md in this project.

Our project defines a Datomic database (along with virtual attributes) via a Fulcro RAD attribute model. The attribute options are defined in the namespace com.fulcrologic.rad.attributes-options. Our model is defined in the source folder @src/main/myapp/model_rad, with the model.cljc file being the join point for everything.

Each entity in our database model has a model file (e.g. src/main/myapp/model_rad/invoice.cljc), though entity attributes are actually grouped around an "identity" attribute (i.e. any defattr with ao/identity? set to true.)

The grouping is done with ao/identities, which is a set of id attributes whose entities CAN include that attribute. For example ao/identities #{:product/id :invoice/id} would be that the attribute could appear on products or invoices.

A defattr MAY have an optional docstring just after the symbol (just like def). So the signature is (defattr sym docstring? database-keyword type options-map). The type is database specific, but most common types like :int, :string, :keyword, and :ref are supported by Datomic.

The :ref type indicates that the attribute points to one (or many if the ao/cardinality is set to :many) entity. The value of ao/target or ao/targets will specify id attributes of the target entities of the reference.

From this you can deduce a lot about the data model, and in fact namespaces like myapp.lib.rad.introspection do just that.

The RAD model is used to generate many things: database schema, pathom resolvers, validations (malli schemas), reports (see defsc-report) forms (defsc-form), import/export formats (csv, excel, etc.).

The legacy code has "builders" for making instances of objects for tests. In the newer code, we prefer a pattern where, in the RAD model file, we add a function called new-MODELNAME, e.g. new-product. Such functions should look like this:

(defn new-product
  "Create a product. The name will be the sku and temporary ID of the product. "
  [sku & {:as addl-attrs}]
  (merge
    {:db/id                      sku
     :product/id                 (new-uuid)
     :product/sku                sku
     :product/description        sku
     :product/inventory-tracked? false}
    addl-attrs))

Where the bare minimum arguments for a usable entity are included, and the user can specify named args to override/fill in things that we give defaults for. Note that Datomic allows us to use strings as a :db/id, and those will be unified among entities on a single transaction. The :tempids of the datomic result will then include those strings as keys to the native :db/id of the created entities. This allows us to quickly build things for tests:

(let [c    (new-company "Acme") ; sets :db/id to "Acme"
      ;; assigns a alt description and relates the new product to the company
      p    (new-product "sku-100" :product/company "Acme" :product/description "My Product") 
      conn (test-conn)
      {{:strs [Acme sku-100]} :tempids} (d/transact conn {:tx-data [p c]})]
  ...)

You should never change an existing "errant" builder function, since they are widely used in tests.