Liking cljdoc? Tell your friends :D

pgmalli.impl.eval

Evaluates CHECK expression data against a row the way PostgreSQL does: nil is NULL, comparisons and functions yield nil when an operand is nil, and a CHECK passes unless its result is false. AND, OR and COALESCE stop at the first decisive operand, left to right. An expression PostgreSQL would fail on (division by zero, a cast that does not parse) fails the row, since the database would reject it too. Rows hold the registry's types (java.time, UUID, jsonb as maps and vectors).

Only the vocabulary that occurs in CHECK constraints is implemented; supported? tells whether an expression is inside it, and render leaves the others unrendered.

Evaluates CHECK expression data against a row the way PostgreSQL does: nil is NULL,
comparisons and functions yield nil when an operand is nil, and a CHECK passes unless its
result is false. AND, OR and COALESCE stop at the first decisive operand, left to right. An
expression PostgreSQL would fail on (division by zero, a cast that does not parse) fails
the row, since the database would reject it too. Rows hold the registry's types (java.time,
UUID, jsonb as maps and vectors).

Only the vocabulary that occurs in CHECK constraints is implemented; supported? tells
whether an expression is inside it, and render leaves the others unrendered.
raw docstring

pgmalli.impl.expr

Turns expressions as printed by PostgreSQL's deparser (pg_get_constraintdef, pg_get_expr) into HoneySQL-style data. Only that output format is supported, not arbitrary SQL.

Covered: comparison, logical, arithmetic, string, array, jsonb and regex operators (see edn-safe-ops); IS [NOT] NULL/TRUE/FALSE; IS [NOT] DISTINCT FROM; [NOT] IN; ANY/ALL (ARRAY[...]); [NOT] BETWEEN [SYMMETRIC]; [NOT] LIKE/ILIKE; ::casts; function calls; TRIM(BOTH FROM x); CASE; CURRENT_TIMESTAMP and friends; AT TIME ZONE; (x).field; x[i]; quoted identifiers; string, number, boolean and NULL literals.

Operators whose symbol is not a readable EDN keyword (~, @>, ...) get a named keyword (see edn-safe-ops); ->honeysql maps them back when SQL has to be generated.

Turns expressions as printed by PostgreSQL's deparser (pg_get_constraintdef, pg_get_expr)
into HoneySQL-style data. Only that output format is supported, not arbitrary SQL.

Covered: comparison, logical, arithmetic, string, array, jsonb and regex operators (see
edn-safe-ops); IS [NOT] NULL/TRUE/FALSE; IS [NOT] DISTINCT FROM; [NOT] IN; ANY/ALL (ARRAY[...]);
[NOT] BETWEEN [SYMMETRIC]; [NOT] LIKE/ILIKE; ::casts; function calls; TRIM(BOTH FROM x);
CASE; CURRENT_TIMESTAMP and friends; AT TIME ZONE; (x).field; x[i]; quoted identifiers;
string, number, boolean and NULL literals.

Operators whose symbol is not a readable EDN keyword (~, @>, ...) get a named keyword
(see edn-safe-ops); ->honeysql maps them back when SQL has to be generated.
raw docstring

pgmalli.impl.generate

Config -> generated EDN files, one per schema.

Config: {:schemas ["public"] ; default ["public"] :out-dir "resources/pgmalli" ; default; files are <out-dir>/<schema>.edn :overrides {constraint-name schema-or-{:skip reason}} :db {:host :port :db :user :password :sslmode :psql :dir}} ; optional; psql's environment otherwise

File contents: {:schema "public" :database-version "PostgreSQL 17.x ..." :registry {name schema} :unrendered [fact ...] :skipped [fact ...]}

Output is deterministic (sorted maps, pprint). Overrides that are not EDN (functions) are rejected at generation time.

Config -> generated EDN files, one per schema.

Config:
  {:schemas ["public"]           ; default ["public"]
   :out-dir "resources/pgmalli"  ; default; files are <out-dir>/<schema>.edn
   :overrides {constraint-name schema-or-{:skip reason}}
   :db {:host :port :db :user :password :sslmode :psql :dir}}  ; optional; psql's environment otherwise

File contents:
  {:schema "public" :database-version "PostgreSQL 17.x ..."
   :registry {name schema} :unrendered [fact ...] :skipped [fact ...]}

Output is deterministic (sorted maps, pprint). Overrides that are not EDN (functions)
are rejected at generation time.
raw docstring

pgmalli.impl.ir

Reads the structure of one schema from pg_catalog through psql.

Connection settings are psql's own (PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD, PGSSLMODE, ~/.pgpass); entries in the db map override them for the call.

Result shape: {:name "public" :database_version "PostgreSQL 17.x ..." :tables {"users" {:name "users" :columns [{:name :position :data_type :type_schema :is_nullable :default_value :generated_expr :identity :max_length :precision :scale}] :constraints {"users_age_check" {:name :type :columns :check_clause :is_valid :nulls_not_distinct :references}}}} :types {"mood" {:kind "ENUM" :enum_values [...]} "email" {:kind "DOMAIN" :base_type :not_null :default :constraints [{:name :definition}]}}} :type is one of "CHECK", "PRIMARY KEY", "UNIQUE", "FOREIGN KEY"; :references is {:match :schema :table :columns} for foreign keys, :match one of "SIMPLE", "FULL", "PARTIAL"; :nulls_not_distinct is set for UNIQUE constraints. Maps keyed by object name (:tables, :constraints, :types) keep string keys; everything else is keywordized. Expressions are the strings PostgreSQL's deparser produces.

Reads the structure of one schema from pg_catalog through psql.

Connection settings are psql's own (PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD,
PGSSLMODE, ~/.pgpass); entries in the db map override them for the call.

Result shape:
  {:name "public" :database_version "PostgreSQL 17.x ..."
   :tables {"users" {:name "users"
                     :columns [{:name :position :data_type :type_schema :is_nullable
                                :default_value :generated_expr :identity :max_length :precision :scale}]
                     :constraints {"users_age_check" {:name :type :columns :check_clause :is_valid :nulls_not_distinct :references}}}}
   :types {"mood" {:kind "ENUM" :enum_values [...]}
           "email" {:kind "DOMAIN" :base_type :not_null :default :constraints [{:name :definition}]}}}
:type is one of "CHECK", "PRIMARY KEY", "UNIQUE", "FOREIGN KEY"; :references is
{:match :schema :table :columns} for foreign keys, :match one of "SIMPLE", "FULL", "PARTIAL";
:nulls_not_distinct is set for UNIQUE constraints. Maps keyed by object name (:tables, :constraints,
:types) keep string keys; everything else is keywordized. Expressions are the strings
PostgreSQL's deparser produces.
raw docstring

pgmalli.impl.json

JSON text -> data, with whichever parser the runtime has: babashka ships cheshire and cannot load data.json; the JVM uses data.json.

JSON text -> data, with whichever parser the runtime has: babashka ships cheshire and cannot
load data.json; the JVM uses data.json.
raw docstring

pgmalli.impl.pattern

Facts about a schema, derived from the structure read by pgmalli.impl.ir.

A fact is a map with :fact (the kind), :schema, and :table / :column / :constraint where they apply. CHECK constraints are matched against a fixed set of patterns (column patterns, then :branch-check and :or-check); anything else is kept as :table-check with the expression data, never dropped.

Kinds: :enum-type an enum type of the schema {:type-name :values} :column a column {:type :position :nullable? :default :identity :generated} :identity is :always, :default or :serial (a nextval default); :generated is the expression :enum column of an enum type {:type-name :values} :domain-ref column of a domain type {:type-name :base} :unknown-type type outside the mapping table (rendered as :any) {:type} :max-length varchar(n) {:max} :numeric numeric(p,s) {:precision :scale} :in-set col IN (...) / col = v {:values} :not-in-set col NOT IN (...) / col <> v {:values} :range col >= a AND col <= b, BETWEEN, ... {:min :max :min-exclusive? :max-exclusive?} :non-blank length(trim(col)) > 0 / col <> '' {:trim?} :length length(col) <= n, cardinality(col) > 0 {:fn :min :max :exact} :json-type jsonb_typeof(col) = 'object' {:json-type} :regex col ~ 're' {:re :case-insensitive?} :like col LIKE 'p' {:pattern :case-insensitive?} :not-null col IS NOT NULL :null col IS NULL :when-present col IS NULL OR <column pattern> {:fact-when-present} :primary-key table primary key {:columns} :unique UNIQUE constraint {:columns :nulls-distinct? (false for NULLS NOT DISTINCT)} :references FOREIGN KEY {:columns :match (:simple or :full) :to {:schema :table :columns}} :domain domain type {:type-name :base :not-null? :default :facts (column patterns over VALUE)} :domain-check CHECK of a domain that matched no pattern {:type-name :constraint :expr :valid?} :branch-check CHECK of the form col = v AND ... OR col = w AND ... {:dispatch :branches [{:values :facts} or {:null true :facts}] :default} :or-check CHECK whose OR alternatives are each an AND of column patterns {:alternatives [[fact ...] ...]} :table-check CHECK that matched no pattern {:expr :columns :valid?} :unparsed expression that could not be read {:input :error}

One CHECK can yield several facts (column patterns joined by AND); every fact from a CHECK carries the whole expression as :expr. NOT VALID constraints are never matched, since existing rows may violate them.

Facts about a schema, derived from the structure read by pgmalli.impl.ir.

A fact is a map with :fact (the kind), :schema, and :table / :column / :constraint where they
apply. CHECK constraints are matched against a fixed set of patterns (column patterns, then
:branch-check and :or-check); anything else is kept as :table-check with the expression data,
never dropped.

Kinds:
  :enum-type    an enum type of the schema           {:type-name :values}
  :column       a column                              {:type :position :nullable? :default :identity :generated}
                :identity is :always, :default or :serial (a nextval default); :generated is the expression
  :enum         column of an enum type                {:type-name :values}
  :domain-ref   column of a domain type               {:type-name :base}
  :unknown-type type outside the mapping table (rendered as :any) {:type}
  :max-length   varchar(n)                            {:max}
  :numeric      numeric(p,s)                          {:precision :scale}
  :in-set       col IN (...) / col = v                {:values}
  :not-in-set   col NOT IN (...) / col <> v            {:values}
  :range        col >= a AND col <= b, BETWEEN, ...   {:min :max :min-exclusive? :max-exclusive?}
  :non-blank    length(trim(col)) > 0 / col <> ''     {:trim?}
  :length       length(col) <= n, cardinality(col) > 0 {:fn :min :max :exact}
  :json-type    jsonb_typeof(col) = 'object'          {:json-type}
  :regex        col ~ 're'                            {:re :case-insensitive?}
  :like         col LIKE 'p'                          {:pattern :case-insensitive?}
  :not-null     col IS NOT NULL
  :null         col IS NULL
  :when-present col IS NULL OR <column pattern>       {:fact-when-present}
  :primary-key  table primary key                      {:columns}
  :unique       UNIQUE constraint                      {:columns :nulls-distinct? (false for NULLS NOT DISTINCT)}
  :references   FOREIGN KEY                            {:columns :match (:simple or :full) :to {:schema :table :columns}}
  :domain       domain type                            {:type-name :base :not-null? :default :facts (column patterns over VALUE)}
  :domain-check CHECK of a domain that matched no pattern {:type-name :constraint :expr :valid?}
  :branch-check CHECK of the form col = v AND ... OR col = w AND ...
                                                       {:dispatch :branches [{:values :facts} or {:null true :facts}] :default}
  :or-check     CHECK whose OR alternatives are each an AND of column patterns
                                                       {:alternatives [[fact ...] ...]}
  :table-check  CHECK that matched no pattern         {:expr :columns :valid?}
  :unparsed     expression that could not be read     {:input :error}

One CHECK can yield several facts (column patterns joined by AND); every fact from a CHECK
carries the whole expression as :expr. NOT VALID constraints are never matched, since
existing rows may violate them.
raw docstring

pgmalli.impl.render

Facts -> malli schemas.

registry returns {:registry {name schema} :unrendered [fact] :skipped [fact]} with :pg.<schema>/<type> enum types and domains (a domain CHECK outside the patterns is [:pg/check-value expr], evaluated over the value as :VALUE) :pg.<schema>/<table> a valid row as read from the database A row schema is [:map ...] alone, or [:and [:map ...] checks...] when the table has constraints across columns: [:multi ...] for branches on one column's value, [:or ...] of map fragments, and [:pg/check expr] for everything else pgmalli.impl.eval can evaluate; bytea columns with a length CHECK are [:pg/bytes {:min :max}]. Insert schemas are derived from row schemas when a registry is loaded (pgmalli.impl.runtime).

Properties: on the map :pg/table ("schema.table"), :pg/primary-key, :pg/unique ({:columns} each, :nulls-distinct false for NULLS NOT DISTINCT) and :pg/foreign-keys ({:columns :table :to} each, tables schema-qualified, :match :full for MATCH FULL); on columns :pg/type :pg/default :pg/identity :pg/generated :pg/constraint, and malli's :default for literal defaults.

Identifiers that are not plain names become string keys, keeping the output readable EDN. overrides is {constraint-name schema-or-{:skip reason}}.

Facts -> malli schemas.

registry returns {:registry {name schema} :unrendered [fact] :skipped [fact]} with
  :pg.<schema>/<type>     enum types and domains (a domain CHECK outside the patterns is
                          [:pg/check-value expr], evaluated over the value as :VALUE)
  :pg.<schema>/<table>    a valid row as read from the database
A row schema is [:map ...] alone, or [:and [:map ...] checks...] when the table has constraints
across columns: [:multi ...] for branches on one column's value, [:or ...] of map fragments,
and [:pg/check expr] for everything else pgmalli.impl.eval can evaluate; bytea columns with a
length CHECK are [:pg/bytes {:min :max}]. Insert schemas are
derived from row schemas when a registry is loaded (pgmalli.impl.runtime).

Properties: on the map :pg/table ("schema.table"), :pg/primary-key, :pg/unique
({:columns} each, :nulls-distinct false for NULLS NOT DISTINCT) and :pg/foreign-keys
({:columns :table :to} each, tables schema-qualified, :match :full for MATCH FULL); on columns :pg/type
:pg/default :pg/identity :pg/generated :pg/constraint, and malli's :default for literal defaults.

Identifiers that are not plain names become string keys, keeping the output readable EDN.
overrides is {constraint-name schema-or-{:skip reason}}.
raw docstring

pgmalli.impl.runtime

The application side: generated files as malli registries, plus helpers that need malli. Generated files are read from the classpath as pgmalli/<schema>.edn.

The application side: generated files as malli registries, plus helpers that need malli.
Generated files are read from the classpath as pgmalli/<schema>.edn.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close