Liking cljdoc? Tell your friends :D

boundary.admin.core.schema-introspection

Pure functions for database schema introspection and entity configuration.

This namespace contains pure business logic for transforming raw database metadata into UI-friendly entity configurations. All functions are pure (no side effects) and testable without database connections.

Key responsibilities:

  • Parse database column metadata into field configurations
  • Infer appropriate UI widgets from database types
  • Detect relationships and foreign keys
  • Merge auto-detected configuration with manual overrides
  • Generate sensible defaults for labels and field ordering
Pure functions for database schema introspection and entity configuration.

This namespace contains pure business logic for transforming raw database
metadata into UI-friendly entity configurations. All functions are pure
(no side effects) and testable without database connections.

Key responsibilities:
- Parse database column metadata into field configurations
- Infer appropriate UI widgets from database types
- Detect relationships and foreign keys
- Merge auto-detected configuration with manual overrides
- Generate sensible defaults for labels and field ordering
raw docstring

apply-field-orderclj

(apply-field-order fields field-order)

Apply preferred field ordering to a vector of fields.

Uses stable sorting: fields in :field-order come first (in that order), remaining fields are appended in their original order.

Args: fields: Vector of field keywords to reorder field-order: Optional vector of preferred field order

Returns: Reordered vector of field keywords

Example: (apply-field-order [:c :a :b :d] [:a :b]) ;=> [:a :b :c :d]

(apply-field-order [:email :name :role :active] [:role :email]) ;=> [:role :email :name :active]

Apply preferred field ordering to a vector of fields.

Uses stable sorting: fields in :field-order come first (in that order),
remaining fields are appended in their original order.

Args:
  fields: Vector of field keywords to reorder
  field-order: Optional vector of preferred field order

Returns:
  Reordered vector of field keywords

Example:
  (apply-field-order [:c :a :b :d] [:a :b])
  ;=> [:a :b :c :d]

  (apply-field-order [:email :name :role :active] [:role :email])
  ;=> [:role :email :name :active]
sourceraw docstring

apply-field-order-to-configclj

(apply-field-order-to-config entity-config)

Apply :field-order to :editable-fields and :detail-fields in entity config.

If :field-order is present in the config, reorders :editable-fields and :detail-fields accordingly. Does not modify :list-fields (those have their own explicit ordering).

Args: entity-config: Entity configuration map

Returns: Entity configuration with reordered field vectors

Example: (apply-field-order-to-config {:editable-fields [:c :a :b] :detail-fields [:c :a :b :d] :field-order [:a :b :c]})

Apply :field-order to :editable-fields and :detail-fields in entity config.

If :field-order is present in the config, reorders :editable-fields and
:detail-fields accordingly. Does not modify :list-fields (those have their
own explicit ordering).

Args:
  entity-config: Entity configuration map

Returns:
  Entity configuration with reordered field vectors

Example:
  (apply-field-order-to-config
    {:editable-fields [:c :a :b]
     :detail-fields [:c :a :b :d]
     :field-order [:a :b :c]})
sourceraw docstring

build-entity-configclj

(build-entity-config auto-config manual-config)

Build complete entity configuration by merging auto-detected with manual.

This is the main function that combines schema introspection results with user-provided configuration overrides.

Args: auto-config: Entity configuration from parse-table-metadata manual-config: Manual configuration overrides (can be nil or partial)

Returns: Complete merged entity configuration

Example: (build-entity-config {:label "Users" :fields {...} :list-fields [...]} {:label "System Users" :list-fields [:email :name :role]})

Build complete entity configuration by merging auto-detected with manual.

This is the main function that combines schema introspection results
with user-provided configuration overrides.

Args:
  auto-config: Entity configuration from parse-table-metadata
  manual-config: Manual configuration overrides (can be nil or partial)

Returns:
  Complete merged entity configuration

Example:
  (build-entity-config
    {:label "Users" :fields {...} :list-fields [...]}
    {:label "System Users" :list-fields [:email :name :role]})
sourceraw docstring

common-hidden-fieldsclj

Set of field names that are typically hidden in admin UI (in kebab-case).

Set of field names that are typically hidden in admin UI (in kebab-case).
sourceraw docstring

common-readonly-fieldsclj

Set of field names that are typically readonly (in kebab-case).

Set of field names that are typically readonly (in kebab-case).
sourceraw docstring

detect-foreign-keysclj

(detect-foreign-keys fields-by-name)

Detect foreign key relationships from field names.

Week 2: Heuristic based on field naming conventions. Week 3+: Could enhance with actual database foreign key constraints.

Args: fields-by-name: Map of field-name -> field-config

Returns: Vector of relationship maps: [{:field :user-id :references-entity :users :references-field :id :display-field :name}]

Example: (detect-foreign-keys {:user-id {...} :category-id {...}})

Detect foreign key relationships from field names.

Week 2: Heuristic based on field naming conventions.
Week 3+: Could enhance with actual database foreign key constraints.

Args:
  fields-by-name: Map of field-name -> field-config

Returns:
  Vector of relationship maps:
  [{:field :user-id
    :references-entity :users
    :references-field :id
    :display-field :name}]

Example:
   (detect-foreign-keys {:user-id {...} :category-id {...}})
sourceraw docstring

detect-relationshipsclj

(detect-relationships entity-config)

Detect all relationships for an entity configuration.

Week 2: Detects belongs-to relationships from foreign key fields. Week 3+: Could add has-many and has-one detection.

Args: entity-config: Entity configuration map

Returns: Entity configuration with :relationships key added

Example: (detect-relationships {:label "Orders" :fields {...}})

Detect all relationships for an entity configuration.

Week 2: Detects belongs-to relationships from foreign key fields.
Week 3+: Could add has-many and has-one detection.

Args:
  entity-config: Entity configuration map

Returns:
  Entity configuration with :relationships key added

Example:
  (detect-relationships {:label "Orders" :fields {...}})
sourceraw docstring

extract-enum-fields-from-malli-schemaclj

(extract-enum-fields-from-malli-schema schema)

Extract enum field configurations from a raw Malli :map schema.

Walks the map children and returns a partial field config for every field whose schema is [:enum v1 v2 ...]. Works on raw Malli schema data (no compilation / malli.core dependency needed).

Args: schema: Raw Malli schema data, expected to be a :map vector such as [:map {} [:role [:enum :admin :user]] [:theme {:optional true} [:enum :light :dark]]]

Returns: Map of field-name keyword → {:type :enum :widget :select :options [...]} Options are [value label] pairs where label is a humanised string. Returns {} when schema is nil or not a :map schema.

Example: (extract-enum-fields-from-malli-schema [:map {} [:role [:enum :admin :user :viewer]]]) ;=> {:role {:type :enum :widget :select ; :options [[:admin "Admin"] [:user "User"] [:viewer "Viewer"]]}}

Extract enum field configurations from a raw Malli :map schema.

Walks the map children and returns a partial field config for every field
whose schema is [:enum v1 v2 ...].  Works on raw Malli schema data (no
compilation / malli.core dependency needed).

Args:
  schema: Raw Malli schema data, expected to be a :map vector such as
          [:map {} [:role [:enum :admin :user]] [:theme {:optional true}
                                                 [:enum :light :dark]]]

Returns:
  Map of field-name keyword → {:type :enum :widget :select :options [...]}
  Options are [value label] pairs where label is a humanised string.
  Returns {} when schema is nil or not a :map schema.

Example:
  (extract-enum-fields-from-malli-schema
    [:map {} [:role [:enum :admin :user :viewer]]])
  ;=> {:role {:type :enum :widget :select
  ;           :options [[:admin "Admin"] [:user "User"] [:viewer "Viewer"]]}}
sourceraw docstring

humanize-entity-nameclj

(humanize-entity-name entity-name)

Convert entity name to human-readable label (pluralized).

Args: entity-name: Keyword entity name

Returns: String display label

Examples: (humanize-entity-name :user) ;=> "Users" (humanize-entity-name :item) ;=> "Items" (humanize-entity-name :category) ;=> "Categories"

Convert entity name to human-readable label (pluralized).

Args:
  entity-name: Keyword entity name

Returns:
  String display label

Examples:
  (humanize-entity-name :user)    ;=> "Users"
  (humanize-entity-name :item)    ;=> "Items"
  (humanize-entity-name :category) ;=> "Categories"
sourceraw docstring

humanize-field-nameclj

(humanize-field-name field-name)

Convert field name to human-readable label.

Converts kebab-case or snake_case to Title Case.

Args: field-name: Keyword field name

Returns: String display label

Examples: (humanize-field-name :email) ;=> "Email" (humanize-field-name :first-name) ;=> "First Name" (humanize-field-name :created_at) ;=> "Created At" (humanize-field-name :mfa-enabled) ;=> "Mfa Enabled"

Convert field name to human-readable label.

Converts kebab-case or snake_case to Title Case.

Args:
  field-name: Keyword field name

Returns:
  String display label

Examples:
  (humanize-field-name :email)        ;=> "Email"
  (humanize-field-name :first-name)   ;=> "First Name"
  (humanize-field-name :created_at)   ;=> "Created At"
  (humanize-field-name :mfa-enabled)  ;=> "Mfa Enabled"
sourceraw docstring

infer-field-typeclj

(infer-field-type sql-type)
(infer-field-type sql-type field-name)

Infer logical field type from SQL/database type.

Args: sql-type: String SQL type from database metadata field-name: (Optional) Keyword field name for heuristics

Returns: Keyword field type (:uuid, :string, :int, etc.) Defaults to :string if type is not recognized

Examples: (infer-field-type "VARCHAR(255)") ;=> :string (infer-field-type "INTEGER") ;=> :int (infer-field-type "BOOLEAN") ;=> :boolean (infer-field-type "TIMESTAMP") ;=> :instant (infer-field-type "TEXT" :created-at) ;=> :instant (heuristic) (infer-field-type "TEXT" :email) ;=> :string (heuristic) (infer-field-type "UNKNOWN_TYPE") ;=> :string

Infer logical field type from SQL/database type.

Args:
  sql-type: String SQL type from database metadata
  field-name: (Optional) Keyword field name for heuristics

Returns:
  Keyword field type (:uuid, :string, :int, etc.)
  Defaults to :string if type is not recognized

Examples:
  (infer-field-type "VARCHAR(255)")      ;=> :string
  (infer-field-type "INTEGER")          ;=> :int
  (infer-field-type "BOOLEAN")          ;=> :boolean
  (infer-field-type "TIMESTAMP")        ;=> :instant
  (infer-field-type "TEXT" :created-at) ;=> :instant (heuristic)
  (infer-field-type "TEXT" :email)      ;=> :string (heuristic)
  (infer-field-type "UNKNOWN_TYPE")     ;=> :string
sourceraw docstring

infer-widget-for-fieldclj

(infer-widget-for-field field-name field-type _sql-type)

Infer appropriate UI widget for a field based on its characteristics.

Args: field-name: Keyword field name (used for heuristics) field-type: Keyword field type (:uuid, :string, :int, etc.) sql-type: Original SQL type string (for additional context)

Returns: Keyword widget type (:text-input, :email-input, :checkbox, etc.)

Examples: (infer-widget-for-field :email :string "VARCHAR") ;=> :email-input (infer-widget-for-field :password :string "VARCHAR") ;=> :password-input (infer-widget-for-field :active :boolean "BOOLEAN") ;=> :checkbox (infer-widget-for-field :created-at :instant "TIMESTAMP") ;=> :datetime-input

Infer appropriate UI widget for a field based on its characteristics.

Args:
  field-name: Keyword field name (used for heuristics)
  field-type: Keyword field type (:uuid, :string, :int, etc.)
  sql-type: Original SQL type string (for additional context)

Returns:
  Keyword widget type (:text-input, :email-input, :checkbox, etc.)

Examples:
  (infer-widget-for-field :email :string "VARCHAR")     ;=> :email-input
  (infer-widget-for-field :password :string "VARCHAR")  ;=> :password-input
  (infer-widget-for-field :active :boolean "BOOLEAN")   ;=> :checkbox
   (infer-widget-for-field :created-at :instant "TIMESTAMP") ;=> :datetime-input
sourceraw docstring

merge-field-configclj

(merge-field-config auto-config manual-config)

Merge auto-detected field config with manual overrides.

Args: auto-config: Field configuration from schema introspection manual-config: Manual overrides map (can be nil)

Returns: Merged field configuration with manual overrides applied

Example: (merge-field-config {:name :email :widget :text-input} {:widget :email-input :required true})

Merge auto-detected field config with manual overrides.

Args:
  auto-config: Field configuration from schema introspection
  manual-config: Manual overrides map (can be nil)

Returns:
  Merged field configuration with manual overrides applied

Example:
  (merge-field-config {:name :email :widget :text-input}
                     {:widget :email-input :required true})
sourceraw docstring

merge-fields-configclj

(merge-fields-config auto-fields manual-fields)

Merge all field configurations with manual overrides.

Args: auto-fields: Map of field-name -> auto-detected field config manual-fields: Map of field-name -> manual field config (can be nil)

Returns: Merged fields map

Example: (merge-fields-config {:email {...} :name {...}} {:email {:widget :email-input}})

Merge all field configurations with manual overrides.

Args:
  auto-fields: Map of field-name -> auto-detected field config
  manual-fields: Map of field-name -> manual field config (can be nil)

Returns:
  Merged fields map

Example:
  (merge-fields-config {:email {...} :name {...}}
                      {:email {:widget :email-input}})
sourceraw docstring

normalize-sql-typeclj

(normalize-sql-type sql-type)

Normalize SQL type string to lowercase without size/precision.

Args: sql-type: String SQL type (e.g., 'VARCHAR(255)', 'DECIMAL(10,2)')

Returns: Normalized lowercase type string without size

Examples: (normalize-sql-type "VARCHAR(255)") ;=> "varchar" (normalize-sql-type "DECIMAL(10,2)") ;=> "decimal" (normalize-sql-type "INTEGER") ;=> "integer" (normalize-sql-type "TIMESTAMP") ;=> "timestamp"

Normalize SQL type string to lowercase without size/precision.

Args:
  sql-type: String SQL type (e.g., 'VARCHAR(255)', 'DECIMAL(10,2)')

Returns:
  Normalized lowercase type string without size

Examples:
  (normalize-sql-type "VARCHAR(255)")      ;=> "varchar"
  (normalize-sql-type "DECIMAL(10,2)")    ;=> "decimal"
  (normalize-sql-type "INTEGER")          ;=> "integer"
  (normalize-sql-type "TIMESTAMP")        ;=> "timestamp"
sourceraw docstring

parse-column-metadataclj

(parse-column-metadata column-meta)

Parse single database column into field configuration.

Args: column-meta: Map with column metadata from database: {:name "email" :type "varchar" :not-null true :default nil :primary-key false}

Returns: Field configuration map: {:name :email :label "Email" :type :string :widget :email-input :required true :readonly false :hidden false :searchable true :sortable true :filterable true}

Example: (parse-column-metadata {:name "email" :type "VARCHAR(255)" :not-null true :primary-key false})

Parse single database column into field configuration.

Args:
  column-meta: Map with column metadata from database:
               {:name "email"
                :type "varchar"
                :not-null true
                :default nil
                :primary-key false}

Returns:
  Field configuration map:
  {:name :email
   :label "Email"
   :type :string
   :widget :email-input
   :required true
   :readonly false
   :hidden false
   :searchable true
   :sortable true
   :filterable true}

Example:
  (parse-column-metadata {:name "email"
                         :type "VARCHAR(255)"
                         :not-null true
                         :primary-key false})
sourceraw docstring

parse-table-metadataclj

(parse-table-metadata table-name columns-meta)

Parse database table metadata into entity configuration.

Takes raw database column metadata and produces a complete entity configuration with sensible defaults for all fields.

Args: table-name: Keyword table name columns-meta: Vector of column metadata maps from database

Returns: Entity configuration map with:

  • Field configurations for all columns
  • Default field lists (list, detail, editable, etc.)
  • Primary key identification
  • Auto-generated entity label

Example: (parse-table-metadata :users [{:name "id" :type "UUID" :primary-key true} {:name "email" :type "VARCHAR(255)" :not-null true} {:name "created_at" :type "TIMESTAMP" :not-null true}])

Parse database table metadata into entity configuration.

Takes raw database column metadata and produces a complete entity
configuration with sensible defaults for all fields.

Args:
  table-name: Keyword table name
  columns-meta: Vector of column metadata maps from database

Returns:
  Entity configuration map with:
  - Field configurations for all columns
  - Default field lists (list, detail, editable, etc.)
  - Primary key identification
  - Auto-generated entity label

Example:
  (parse-table-metadata :users
    [{:name "id" :type "UUID" :primary-key true}
     {:name "email" :type "VARCHAR(255)" :not-null true}
     {:name "created_at" :type "TIMESTAMP" :not-null true}])
sourceraw docstring

should-be-hidden?clj

(should-be-hidden? field-name)

Determine if field should be hidden in admin UI.

Args: field-name: Keyword field name

Returns: Boolean true if field should be hidden

Examples: (should-be-hidden? :password-hash) ;=> true (should-be-hidden? :email) ;=> false

Determine if field should be hidden in admin UI.

Args:
  field-name: Keyword field name

Returns:
  Boolean true if field should be hidden

Examples:
  (should-be-hidden? :password-hash) ;=> true
  (should-be-hidden? :email)         ;=> false
sourceraw docstring

should-be-in-list-view?clj

(should-be-in-list-view? field-name field-type)

Determine if field should be shown in table list view.

Some fields are better shown only in detail/edit views, not in the compact table list view.

Args: field-name: Keyword field name field-type: Keyword field type

Returns: Boolean true if field should be in list view

Examples: (should-be-in-list-view? :email :string) ;=> true (should-be-in-list-view? :active :boolean) ;=> false (should-be-in-list-view? :notes :text) ;=> false

Determine if field should be shown in table list view.

Some fields are better shown only in detail/edit views, not in the
compact table list view.

Args:
  field-name: Keyword field name
  field-type: Keyword field type
  
Returns:
  Boolean true if field should be in list view
  
Examples:
  (should-be-in-list-view? :email :string)   ;=> true
  (should-be-in-list-view? :active :boolean) ;=> false
  (should-be-in-list-view? :notes :text)     ;=> false
sourceraw docstring

should-be-readonly?clj

(should-be-readonly? field-name is-primary-key?)

Determine if field should be readonly based on characteristics.

Args: field-name: Keyword field name is-primary-key?: Boolean indicating if field is primary key

Returns: Boolean true if field should be readonly

Examples: (should-be-readonly? :id true) ;=> true (should-be-readonly? :created-at false) ;=> true (should-be-readonly? :name false) ;=> false

Determine if field should be readonly based on characteristics.

Args:
  field-name: Keyword field name
  is-primary-key?: Boolean indicating if field is primary key

Returns:
  Boolean true if field should be readonly

Examples:
  (should-be-readonly? :id true)          ;=> true
  (should-be-readonly? :created-at false) ;=> true
  (should-be-readonly? :name false)       ;=> false
sourceraw docstring

should-be-searchable?clj

(should-be-searchable? field-type field-name)

Determine if field should be searchable.

Args: field-type: Keyword field type field-name: Keyword field name

Returns: Boolean true if field should be searchable

Examples: (should-be-searchable? :string :email) ;=> true (should-be-searchable? :text :description) ;=> true (should-be-searchable? :binary :avatar) ;=> false

Determine if field should be searchable.

Args:
  field-type: Keyword field type
  field-name: Keyword field name

Returns:
  Boolean true if field should be searchable

Examples:
  (should-be-searchable? :string :email) ;=> true
  (should-be-searchable? :text :description) ;=> true
  (should-be-searchable? :binary :avatar) ;=> false
sourceraw docstring

should-be-sortable?clj

(should-be-sortable? field-type)

Determine if field should be sortable.

Args: field-type: Keyword field type

Returns: Boolean true if field should be sortable

Examples: (should-be-sortable? :string) ;=> true (should-be-sortable? :int) ;=> true (should-be-sortable? :json) ;=> false

Determine if field should be sortable.

Args:
  field-type: Keyword field type

Returns:
  Boolean true if field should be sortable

Examples:
  (should-be-sortable? :string) ;=> true
  (should-be-sortable? :int)    ;=> true
  (should-be-sortable? :json)   ;=> false
sourceraw docstring

sql-type->field-typeclj

Mapping from SQL/database types to logical field types.

Keys are lowercase type names as strings (normalized from database). Values are field type keywords used in entity configuration.

Mapping from SQL/database types to logical field types.

Keys are lowercase type names as strings (normalized from database).
Values are field type keywords used in entity configuration.
sourceraw 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