(ns metabase.xrays.domain-entities.specs (:require [malli.core :as mc] [malli.transform :as mtx] [medley.core :as m] [metabase.legacy-mbql.normalize :as mbql.normalize] [metabase.legacy-mbql.util :as mbql.u] [metabase.util.yaml :as yaml])) | |
MBQL clause (ie. a vector starting with a keyword) | (def MBQL
[:fn
{:decode/domain-entity-spec mbql.normalize/normalize
:decode/transform-spec mbql.normalize/normalize
:error/message "valid MBQL clause"}
mbql.u/mbql-clause?]) |
Field type designator -- a keyword derived from | (def FieldType
[:keyword
(letfn [(decoder [k]
(keyword "type" (name k)))]
{:decode/domain-entity-spec decoder
:decode/transform-spec decoder})]) |
(def ^:private DomainEntityReference :string) | |
(def ^:private DomainEntityType
[:and
:keyword
[:fn
{:error/message "Valid DomainEntity"}
#(isa? % :DomainEntity/*)]]) | |
(def ^:private Identifier :string) | |
(def ^:private Description :string) | |
(def ^:private Attributes
[:sequential
[:map
[:field {:optional true} FieldType]
[:domain_entity {:optional true} DomainEntityReference]
[:has_many {:optional true} [:map
[:domain_entity DomainEntityReference]]]]]) | |
(def ^:private BreakoutDimensions
[:sequential
{:decode/domain-entity-spec (fn [breakout-dimensions]
(for [dimension breakout-dimensions]
(if (string? dimension)
(do
(mc/assert FieldType (keyword "type" dimension))
[:dimension dimension])
dimension)))}
MBQL]) | |
(def ^:private ^{:arglists '([m])} add-name-from-key
(partial m/map-kv-vals (fn [k v]
(assoc v :name k)))) | |
(def ^:private LegacyMetrics
[:map-of
{:decode/domain-entity-spec add-name-from-key}
Identifier
[:map
[:aggregation MBQL]
[:name Identifier]
[:breakout {:optional true} BreakoutDimensions]
[:filter {:optional true} MBQL]
[:description {:optional true} Description]]]) | |
(def ^:private Segments
[:map-of
{:decode/domain-entity-spec add-name-from-key}
Identifier
[:map
[:filter MBQL]
[:name Identifier]
[:description {:optional true} Description]]]) | |
Domain entity spec | (def DomainEntitySpec
[:map
[:name DomainEntityReference]
[:type DomainEntityType]
[:required_attributes Attributes]
[:description {:optional true} Description]
[:optional_attributes {:optional true} Attributes]
[:metrics {:optional true} LegacyMetrics]
[:segments {:optional true} Segments]
[:breakout_dimensions {:optional true} BreakoutDimensions]]) |
(defn- add-to-hiearchy!
[{:keys [name refines] :as spec}]
(let [spec-type (keyword "DomainEntity" name)
refines (some->> refines (keyword "DomainEntity"))]
(derive spec-type (or refines :DomainEntity/*))
(-> spec
(dissoc :refines)
(assoc :type spec-type)))) | |
(defn- coerce-to-domain-entity-spec [spec]
(mc/coerce DomainEntitySpec
spec
(mtx/transformer
mtx/string-transformer
mtx/json-transformer
(mtx/transformer {:name :domain-entity-spec})))) | |
(def ^:private domain-entities-dir "domain_entity_specs/") | |
List of registered domain entities. | (def domain-entity-specs
(delay (into {} (for [spec (yaml/load-dir domain-entities-dir (comp coerce-to-domain-entity-spec
add-to-hiearchy!))]
[(:name spec) spec])))) |