================== DMDLユーザーガイド ================== この文書では、Data Model Definition Language (DMDL)およびDMDLコンパイラの利用方法について紹介します。 DMDLの記述 ========== DMDLを利用してデータモデルを定義するには、「DMDLスクリプト」というファイルの中に、データモデルの名前やプロパティの構造を記述します。 DMDLスクリプトは拡張子を :file:`.dmdl` としたUTF-8エンコーディングのテキストファイルで、一つのDMDLスクリプトに複数のデータを定義することも、複数のDMDLスクリプトを利用して必要なデータモデル一式を定義することもできます。 DMDLでは4種類のデータモデルを記述できます。 * `レコードモデルを定義する`_ * `結合モデルを定義する`_ * `集計モデルを定義する`_ * `射影モデルを定義する`_ レコードモデルを定義する ------------------------ レコードモデルはプロパティの一覧を持つデータ構造です。 レコードモデルを定義するには、DMDLスクリプトに次のように記述します。 .. code-block:: none <モデル名> = { <プロパティの一覧> }; それぞれのプロパティは、プロパティ名のあとにプロパティの型を指定します。 また、一つのレコードモデルには複数のプロパティを定義できます。 .. code-block:: none <プロパティの名前> : <プロパティの型> ; モデル名やプロパティ名の形式については `名前の形式`_ を、プロパティに利用可能な型は `プロパティの型`_ を参照して下さい。 以下はモデル名が `example_model` 、プロパティがそれぞれ整数型の `number` , 文字列型の `item_code` , 日時型の `last_updated` である場合の記述です。 .. code-block:: dmdl example_model = { number : INT; item_code : TEXT; last_updated : DATETIME; }; 名前の形式 ~~~~~~~~~~ データモデルやプロパティの名前は、次のような ``snake_case`` の形式でなければなりません。 * 小文字のアルファベット、数字、アンダースコアのみ * 最初の文字と最後の文字にアンダースコアを使えない * アンダースコアを2つ以上続けて使えない * ``_option`` で終わるプロパティ名を使えない また、以下の条件を満たすことを強く推奨しています。 * 名前にはJavaの予約語を利用しない * 名前に含まれる各単語はアルファベットから始める(数字や記号から始めない) [#]_ 以下に名前の指定例を示します。 * よい例 * `hello` * `good_model_name` * `better1` * 悪い例 * `helloWorld` * `BAD_PROPERTY_NAME` * `worse_0` .. [#] 名前の各単語を数字から始めた場合、ある条件下でテストドライバーの一部機能に問題が発生することが報告されています。 プロパティの型 ~~~~~~~~~~~~~~ それぞれのプロパティには次のような型を指定できます。 .. list-table:: 利用可能なプロパティの型 :widths: 3 7 :header-rows: 1 * - 型の名前 - 説明 * - ``INT`` - 32bit符号付き整数 * - ``LONG`` - 64bit符号付き整数 * - ``FLOAT`` - 単精度浮動小数点 * - ``DOUBLE`` - 倍精度浮動小数点 * - ``TEXT`` - 文字列 * - ``DECIMAL`` - 10進数 * - ``DATE`` - 日付 * - ``DATETIME`` - 日時 * - ``BOOLEAN`` - 論理値 * - ``BYTE`` - 8bit符号付き整数 * - ``SHORT`` - 16bit符号付き整数 データモデルを合成する ~~~~~~~~~~~~~~~~~~~~~~ 他で定義したデータモデルを合成して新しいレコードモデルを作成するには、次のように記述します。 .. code-block:: none <定義するモデルの名前> = <合成するモデル1> + <合成するモデル2> + ... ; 合成されたデータモデルは、対象のデータモデルが定義する全てのプロパティを持つことになります。 .. code-block:: dmdl both = left + right; left = { left_value : INT; }; right = { right_value : TEXT; }; 上記の例では、以下のようなデータモデルを定義したことになります。 .. code-block:: dmdl both = { left_value : INT; right_value : TEXT; }; なお、合成するそれぞれのモデルが同じプロパティを定義している場合、そのプロパティは一つだけ定義されたことになります。 また、同じ名前で型が異なるプロパティが定義された場合、データモデルの合成は失敗してエラーになります。 データモデルを拡張する ~~~~~~~~~~~~~~~~~~~~~~ 他のデータモデルに新たにプロパティを追加したデータモデルを定義するには、次のように記述します。 .. code-block:: none <モデル名> = <対象のモデル> + ... + { <プロパティの一覧> }; 拡張されたデータモデルは、対象のデータモデルが定義するすべてのプロパティに加え、新たに定義したプロパティを持つことになります。 .. code-block:: dmdl origin = { value : INT; }; extended = origin + { extra : TEXT; }; 上記の例では、以下のようなデータモデルを定義したことになります。 .. code-block:: dmdl extended = { value : INT; extra : TEXT; }; このようにDMDLでは、他のデータモデルの定義や新たなプロパティの定義を組み合わせて、複雑なデータモデルを定義できます。 結合モデルを定義する -------------------- 結合モデルは、2つのデータモデルに「結合」の操作を行って生成するデータモデルを表します。 出来上がるデータモデルはレコードモデルと同様に複数のプロパティを持つデータ構造ですが、Asakusa DSLの「マスタ結合演算子」で利用した際に結合条件などの情報を自動的に取り出せます。 結合モデルの定義で記述する情報は、以下の通りです。 * 結合対象のデータモデル * 結合条件 (等価結合条件のみ) * 結合前後でのプロパティのマッピング プロパティマッピングを行わない場合、次のような方法で結合モデルを定義します。 .. code-block:: dmdl joined <結合モデル名> = <対象モデル1> % <結合キー1> + <対象モデル2> % <結合キー2>; それぞれの `対象モデル` には、他で定義したデータモデルの名前を指定します。 また、それぞれの `結合キー` には、対象モデルに含まれるプロパティの名前をカンマ区切りで指定します。 上記の形式で定義した結合モデルは、それぞれの対象モデルに定義された全てのプロパティを持ち、それぞれの結合キーを順に等価比較して結合するような構造を表します。 たとえば、次のような結合モデル `item_order` を定義できます。 .. code-block:: dmdl item = { code : LONG; id : TEXT; ... }; order = { item_code : LONG; item_id : TEXT; ... }; joined item_order = item % code, id + order % item_code, item_id; 定義された結合モデルは、 `item` と `order` が定義する全てのプロパティを持ち、 ``item.code = order.item_code`` かつ ``item.id = order.item_id`` という条件で結合可能であることを表す構造になります。 この結合モデル定義の形式は記述が簡潔ですが、対象モデル間に同一のプロパティ名が含まれている場合は利用出来ません。 また、不要なプロパティもすべて含むデータモデルが生成されることに注意が必要です。 これらの問題を回避するためには、以下に示す `プロパティのマッピング`_ を利用して結合モデルを定義します。 プロパティのマッピング ~~~~~~~~~~~~~~~~~~~~~~ 結合時に不要なプロパティを削除したりプロパティの名前を変えるには、結合モデルの定義時にプロパティのマッピングを記述します。 .. code-block:: none joined <結合モデル名> = <対象モデル1> -> { <プロパティのマッピング1> } % <結合キー1> + <対象モデル2> -> { <プロパティのマッピング2> } % <結合キー2>; プロパティのマッピングは、 ``<元のプロパティ名> -> <マッピング後のプロパティ名> ;`` の形式でいくつでも書けます。 また、マッピングを記述しなかったプロパティについては、結合後のデータモデルから除外されます。 .. attention:: プロパティのマッピングを利用する場合、結合キーは **マッピング後の** プロパティ名を指定する必要があります。 また、結合キーになるプロパティはマッピングで削除してはいけません。 以下はプロパティのマッピングを行いながら結合モデルを定義する例です。 .. code-block:: dmdl item = { code : LONG; price : DECIMAL; }; order = { item_code : LONG; amount : INT; datetime : DATETIME; }; joined item_order = item -> { code -> code; price -> price; } % code + order -> { item_code -> code; amount -> total; } % code; 上記の例で、 `item_order` にはそれぞれ `code` , `price` , `total` という3つのプロパティが定義されます。 それぞれのプロパティには、順に結合前の `item.code` ( = `order.item_code` ) , `item.price` , `order.amount` の値がマッピングされます。 なお、 `order.datetime` は結合時に捨てられます。 .. hint:: 結合キーに指定されたプロパティは、他の結合キーに指定されたプロパティと同じ名前にできます。 結合キーは等価結合に使われるので、常に同じ値になるためです。 結合キーの制約 ~~~~~~~~~~~~~~ 結合モデルを定義する際に、それぞれの結合キーは次の制約をすべて満たす必要があります。 * 結合キーに指定したプロパティの個数が一致する * 結合キーに指定したプロパティは、対応するものごとに同じ順序で並んでいる * 結合キーに指定したプロパティは、対応するものごとに同じ型である 集計モデルを定義する -------------------- 集計モデルは、1つのデータモデルに「集計」の操作を行って生成するデータモデルを表します。 出来上がるデータモデルはレコードモデルと同様に複数のプロパティを持つデータ構造ですが、Asakusa DSLの「単純集計演算子」で利用した際にグループ化条件や集約関数などの情報を自動的に取り出せます。 集計モデルの定義で記述する情報は、以下の通りです。 * 集計対象のデータモデル * グループ化条件 * 集計方法 次のような方法で集計モデルを定義します。 .. code-block:: none summarized <集計モデル名> = <対象モデル> => { <集計方法> } % <グループ化キー> ; `対象モデル` には、他で定義したデータモデルの名前を指定します。 `グループ化キー` には集計対象のグループ化に利用するプロパティ名を指定します。 `集計方法` は、次のような形式でいくつでも指定できます。 .. code-block:: none <集約関数> <集計対象のプロパティ名> -> <集計結果のプロパティ名> ; 集計対象のプロパティは、グループ化キーで指定された値ごとにまとめられ、集約関数を適用した上で集計結果のプロパティに格納されます。 利用可能な集約関数は、 `集約関数の種類`_ を参照して下さい。 .. attention:: グループ化キーは **集計結果の** プロパティ名を指定する必要があります。 また、グループ化キーに指定するプロパティは、 ``any`` という集約関数のみを指定できます。 たとえば、次のような集計モデル `item_order` を定義できます。 .. code-block:: dmdl order = { item_code : LONG; price : DECIMAL; ... }; summarized order_summary = order => { any item_code -> code; sum price -> total; count item_code -> count; } % code; 上記の例で、 `order_summary` にはそれぞれ `code` , `total` , `count` という3つのプロパティが定義されます。 集計は `order.item_code` ごとに行われ、それぞれのプロパティには、順に `order.item_code` の値 , `order.price` の合計 , 集計した個数がマッピングされます。 .. hint:: レコードの個数を計測する ``count`` には、グループ化キーになるプロパティを指定すれば、グループの個数を正しく計測できます。 集約関数の種類 ~~~~~~~~~~~~~~ 次のような集約関数を利用できます。 .. list-table:: :widths: 3 7 :header-rows: 1 * - 集約関数 - 性質 * - ``any`` - グループ化した中のいずれか一つの値を利用する * - ``sum`` - グループ化した中の値の合計を利用する * - ``max`` - グループ化した中の最大値を利用する * - ``min`` - グループ化した中の最小値を利用する * - ``count`` - グループ化した中の個数を利用する 集約関数の型マッピング ^^^^^^^^^^^^^^^^^^^^^^ 集約関数を利用した場合、その結果のプロパティ型は以下のように設定されます。 ``=`` は集計元と集計結果でプロパティの型が同じであることを示します。 .. list-table:: :widths: 1 1 1 1 1 1 :header-rows: 1 * - 集計元の型 - ``any`` - ``sum`` - ``max`` - ``min`` - ``count`` * - ``BYTE`` - ``=`` - ``LONG`` - ``=`` - ``=`` - ``LONG`` * - ``SHORT`` - ``=`` - ``LONG`` - ``=`` - ``=`` - ``LONG`` * - ``INT`` - ``=`` - ``LONG`` - ``=`` - ``=`` - ``LONG`` * - ``LONG`` - ``=`` - ``LONG`` - ``=`` - ``=`` - ``LONG`` * - ``DECIMAL`` - ``=`` - ``DECIMAL`` - ``=`` - ``=`` - ``LONG`` * - ``FLOAT`` - ``=`` - ``DOUBLE`` - ``=`` - ``=`` - ``LONG`` * - ``DOUBLE`` - ``=`` - ``DOUBLE`` - ``=`` - ``=`` - ``LONG`` * - ``BOOLEAN`` - ``=`` - N/A - ``=`` - ``=`` - ``LONG`` * - ``DATE`` - ``=`` - N/A - ``=`` - ``=`` - ``LONG`` * - ``DATETIME`` - ``=`` - N/A - ``=`` - ``=`` - ``LONG`` * - ``TEXT`` - ``=`` - N/A - ``=`` - ``=`` - ``LONG`` 射影モデルを定義する -------------------- 射影モデルは、他のモデルの一部を投影するデータモデルです。 射影モデル自体は実体のデータを持たず、他のデータモデルから「射影」として切り出した際のデータ構造を表します。 射影モデルは、Asakusa DSLの :doc:`../dsl/generic-dataflow` 機能と組み合わせて利用します。 多相データフローは、Asakusa DSLで複数のデータモデルに対する共通の処理をまとめて定義するための記述方法です。 詳しくは :doc:`../dsl/generic-dataflow` を参照してください。 射影モデルを定義するには、 ``projective`` というキーワードに続けてレコードモデルと同じ方法でプロパティを定義します。 .. code-block:: none projective <モデル名> = { <プロパティの一覧> }; プロパティの定義方法は、レコードモデルの「 `データモデルを合成する`_ 」や「 `データモデルを拡張する`_ 」と同様に、他のデータモデルのプロパティ定義を利用することも可能です。 データモデルに射影を登録する ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ レコードモデルから射影を取り出すには、対応する射影モデルをレコードモデルにあらかじめ登録しておく必要があります。 レコードモデルに射影モデルを登録するには、レコードモデルの定義時に登録したい射影モデルを合成します。 .. code-block:: none <レコードモデル名> = <射影モデル> + ... ; 射影モデルを合成してレコードモデルを定義した場合、通常のデータモデルを合成した際と同様に、全てのプロパティが定義するレコードモデルに取り込まれます。 .. code-block:: dmdl projective proj_model = { value : INT; }; 上記のように記述した場合、 `proj_model` に対応するJavaのデータモデルクラスは生成されず、代わりに同様のプロパティを持つインターフェースが生成されます。 このインターフェースを実装( ``implements`` )するデータモデルクラスを生成するには、次のようにデータモデル定義の右辺にこの射影モデルを利用します。 .. code-block:: dmdl conc_model = proj_model + { other : INT; }; 射影モデルをデータモデル定義の右辺に利用した場合、その射影モデルが定義するプロパティは、左辺のデータモデルにも自動的に追加されます。 さらに、左辺のデータモデルは右辺に利用したすべての射影モデルをインターフェースとして実装します。 また、射影モデルに別の射影モデルを登録することもできます。 他の射影を持つ射影モデルをデータモデルに登録した場合、データモデルには関係する全ての射影がとりこまれます。 たとえば、以下の例で `record` は、 `sub_proj` , `super_proj` がどちらも射影として登録されます。 .. code-block:: dmdl projective super_proj = { a : INT; }; projective sub_proj = super_proj + { b : INT; }; record = sub_proj; .. _dmdl-property-references: プロパティ参照を定義する ------------------------ レコードモデルおよび射影モデルには、複数のプロパティを単一のコレクションとして利用するための「プロパティ参照」を定義できます。 これらは固定長のリスト (``java.util.List``) またはマップ (``java.util.Map``) として利用でき、それぞれの要素はデータモデル内に存在するプロパティの参照を表します。 つまり、データモデル中のプロパティの値を変更するとリストやマップの値も変化し、リストやマップに対して変更を行うと、対応するプロパティの値が変化します。 このプロパティ参照を上手に利用すると、データモデル内に存在する「プロパティの繰り返し」を容易に処理できるようになります。 リスト型のプロパティ参照を定義する ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ リスト型のプロパティ参照を定義するには、データモデル内に ``<参照名> = {<参照先のプロパティ名>, ...}`` の形式で記述します。 .. code-block:: dmdl m = { a : INT; b : INT; c : INT; ref = {a, b, c}; }; 上記のように記述した場合、 `INT` 型のプロパティ ``a``, ``b``, ``c`` の他に、 ``ref`` という名前のリスト型プロパティ参照を定義します。 このとき、それぞれのプロパティは同じ型である必要があります。 この ``ref`` は要素にそれぞれ ``a``, ``b``, ``c`` の参照を持つ、固定長のリストです。 Javaにおける表現は `プロパティ参照の対応付け`_ を参照してください。 マップ型のプロパティ参照を定義する ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ マップ型のプロパティ参照を定義するには、データモデル内に ``<参照名> = {<キー> : <参照先のプロパティ名>, ...}`` の形式で記述します。 ただし、それぞれのキーは文字列リテラルの形式でなければなりません。 .. code-block:: dmdl m = { a : INT; b : INT; c : INT; ref = { "A" : a, "B" : b, "C" : c, }; }; 上記のように記述した場合、 `INT` 型のプロパティ ``a``, ``b``, ``c`` の他に、 ``ref`` という名前のマップ型プロパティ参照を定義します。 このとき、それぞれのプロパティは同じ型である必要があります。 この ``ref`` という要素にそれぞれ ``a``, ``b``, ``c`` の参照を持ち、それぞれ文字列 ``A``, ``B``, ``C`` のキーが対応づけられた固定長のマップです。 Javaにおける表現は `プロパティ参照の対応付け`_ を参照してください。 コメントの挿入 ============== DMDLスクリプトにコメントを挿入するには、以下のように記述します。 * ``--`` または ``//`` 以下に続く文字列は改行されるまでコメントとみなされます。 * ``/*`` と ``*/`` で囲まれたブロックはコメントとみなされます。これは複数行にわたり有効です。 以下コメントの使用例です。 .. code-block:: dmdl item = { code : LONG; -- XYZコード体系で表現される商品コード id : TEXT; // name : TEXT; }; /* order = { item_code : LONG; item_id : TEXT; name : TEXT; }; */ .. ** 上記では `item` の `code` プロパティの追加説明にコメントを使用しています。 また、 `name` はコメントアウトされているため無効になっています。 `order` はモデル定義の全体がコメントアウトされ無効になっています。 DMDLコンパイラの実行 ==================== 作成したDMDLスクリプトからAsakusa DSLで利用可能なデータモデルを生成するには、DMDLコンパイラを利用します。 データモデルクラスの生成 ------------------------ DMDLスクリプトからJavaデータモデルクラスを生成する場合、Asakusa Frameworkの :file:`asakusa-dmdl-java-*.jar` の :asakusafw-javadoc:`com.asakusafw.dmdl.java.Main` クラスを次の引数で起動します。 .. program:: com.asakusafw.dmdl.java.Main .. option:: -output 出力先のディレクトリ .. option:: -package 生成するクラスのベースパッケージ名 .. option:: -source コンパイルするDMDLスクリプトやディレクトリ .. option:: -sourceencoding DMDLスクリプトのエンコーディング (default: UTF-8) .. option:: -targetencoding 生成するJavaのエンコーディング (default: UTF-8) .. option:: -plugin DMDLコンパイラのプラグインファイル (default: なし) .. note:: ``-plugin`` で指定するコンパイラプラグインについては、 `DMDLコンパイラプラグインの利用`_ も参照してください。 Javaクラスの対応付け -------------------- DMDLコンパイラは、DMDLで定義されたデータモデルごとに、対応するJavaのクラスやインターフェースを生成します。 生成するクラスやインターフェースは、次のような名前になります。 ``<ベースパッケージ名> . <名前空間> . model . <データモデル名>`` ベースパッケージ名 DMDLコンパイラに指定したパッケージ名。 名前空間 「 `データモデルの名前空間`_ 」で指定した名前。 デフォルトは ``dmdl`` 。 データモデル名 DMDLスクリプトで定義したデータモデル名を、CamelCaseの形式 [#]_ に変換したもの。 .. [#] 例: `hello_world` -> `HelloWorld` プロパティの対応付け -------------------- DMDLコンパイラが生成するJavaのクラスやインターフェースには、データモデルに定義したプロパティごとに次の名前の公開メソッドがそれぞれ作成されます。 * ``get <プロパティ名>`` * ``set <プロパティ名>`` * ``get <プロパティ名> Option`` * ``set <プロパティ名> Option`` また、 ``TEXT`` 型のプロパティに限り、追加で下記の公開メソッドが作成されます * ``get <プロパティ名> AsString`` * ``set <プロパティ名> AsString`` それぞれのプロパティの型は、次のようなJavaのデータ型に対応します。 .. list-table:: DMDLとJavaのデータ型 :widths: 3 5 :header-rows: 1 * - 型の名前 - 対応する型 (Option) * - ``INT`` - ``int (IntOption)`` * - ``LONG`` - ``long (LongOption)`` * - ``FLOAT`` - ``float (FloatOption)`` * - ``DOUBLE`` - ``double (DoubleOption)`` * - ``TEXT`` - ``Text (StringOption)`` [#]_ * - ``DECIMAL`` - ``BigDecimal (DecimalOption)`` * - ``DATE`` - ``Date (DateOption)`` [#]_ * - ``DATETIME`` - ``DateTime (DateTimeOption)`` [#]_ * - ``BOOLEAN`` - ``boolean (BooleanOption)`` * - ``BYTE`` - ``byte (ByteOption)`` * - ``SHORT`` - ``short (ShortOption)`` .. [#] ``org.apache.hadoop.io.Text`` , ``...AsString`` は ``java.lang.String`` .. [#] :asakusafw-javadoc:`com.asakusafw.runtime.value.Date` .. [#] :asakusafw-javadoc:`com.asakusafw.runtime.value.DateTime` プロパティ参照の対応付け ------------------------ DMDLコンパイラは、それぞれのプロパティ参照に対して、次の名前の公開メソッドを作成します。 * ``get<参照名>`` また、上記メソッドの返戻値型は、リスト型のプロパティであれば ``java.util.List<プロパティの型>``, マップ型のプロパティであれば ``java.util.Map`` となります。 なお、プロパティ参照を表すリストやマップは、以下の点においてJavaの標準と異なる点に注意が必要です。 * プロパティの追加・削除などは不可能 * ``List.set()`` や ``Map.put()`` などによって値を変更しようとした場合、引数に渡したオブジェクト **そのものを格納せず** 、オブジェクトのコピーを格納する * リストの並び替え (``Collections.sort()``, ``List.sort()`` など) は利用できない データモデルの属性 ================== データモデルに「属性」を定義しておくと、DMDLコンパイラが生成するプログラムを拡張できます。 データモデルの説明 ------------------ データモデルのドキュメンテーションを変更するには、データモデルの定義の直前に ``"<データモデルの説明>"`` を付与します。 .. code-block:: dmdl "サンプルのデータモデル" example = { ... }; データモデルの説明は、レコードモデルだけでなく全てのモデルで指定できます。 データモデルの説明が指定されない場合、データモデルの名前で代用します。 プロパティの説明 ---------------- プロパティのドキュメンテーションを変更するには、プロパティ定義やマッピングの直前に ``"<プロパティの説明>"`` を付与します。 .. code-block:: dmdl order = { "商品コード" item_code : LONG; "商品価格" price : DECIMAL; }; summarized order_summary = order => { "グループ化した商品コード" any item_code -> code; "商品価格の合計" sum price -> total; } % code; プロパティの説明が指定されない場合、プロパティの名前で代用します。 データモデルの名前空間 ---------------------- 生成するプログラムのパッケージ名を(一部)変更するには、データモデル定義の直前に ``@namespace(value = <パッケージ名>)`` を指定します。 このパッケージ名は、データモデルの名前と同様に ``snake_case`` の形式で記述します ( `名前の形式`_ を参照 )。 また、 ``.`` で区切って深い階層の名前も指定できます。 .. code-block:: dmdl "名前空間付きのモデル" @namespace(value = your.namespace) example = { ... }; .. attention:: ``@namespace(value = "ex.a")`` ではなく ``@namespace(value = ex.a)`` のように直接指定します。 .. tip:: データモデルの説明と名前空間を同時に指定する場合、データモデルの説明を先に書きます。 データモデルの名前空間が指定されない場合、 ``dmdl`` という名前空間を利用します。 自動射影 -------- 利用可能なすべての射影をデータモデルに登録させるには、データモデル定義の直前に ``@auto_projection`` を指定します。 射影モデルが持つプロパティをすべて持つモデルに ``@auto_projection`` 属性を指定した場合、そのデータモデルには対象の射影が自動的に登録されます。 .. code-block:: dmdl projective foo = { value1 : INT; value2 : LONG; }; @auto_projection bar = { value1 : INT; value2 : LONG; value3 : DOUBLE; }; 上記のように記述した場合、 `bar` には自動的に `foo` が射影として登録されます。 通常の場合、データモデルに登録される射影は、レコードモデルや射影モデルのプロパティ定義に直接指定された射影モデルのみです。 現在のところ、結合モデルや集計モデルに射影を登録するには、この自動射影を利用する方法のみが提供されています。 プロパティ参照の詳細 ==================== プロパティ参照の型を指定する ---------------------------- プロパティ参照の定義を行う際に、それらの型を明示的に指定することもできます(通常は、要素のプロパティから自動的に推論します)。 プロパティ参照の名前と ``=`` の間に、リスト型であれば ``{<参照先の型>}``, マップ型であれば ``{:<参照先の型>}`` の形式で指定します。 .. code-block:: dmdl m = { a : INT; b : INT; c : INT; ref_list : {INT} = {a, b, c}; ref_alist : {:INT} = { "A" : a, "B" : b, "C" : c, }; }; なお、要素を持たないプロパティ参照を定義する場合、明示的な型の指定が必須になります。 .. code-block:: dmdl m = { ref_list : {INT} = {}; ref_alist : {:TEXT} = {:}; }; プロパティ参照のスタブを定義する -------------------------------- 射影モデル内にプロパティ参照を定義する場合、明示的な参照先のプロパティを省略した「スタブ」を定義することが可能です。 .. code-block:: dmdl projective something = { // INTの参照リスト ref_list : {INT}; // TEXTの参照マップ ref_alist : {:TEXT}; }; プロパティ参照のスタブを持つ射影を合成したモデルにおいては、スタブと同じ名前、同じ型の参照を明示的に定義する必要があります。 プロパティ参照の合成 -------------------- データモデルの合成元にプロパティ参照が含まれる場合、合成先にはそのプロパティ参照が引き継がれます。 .. code-block:: dmdl p0 = { a : INT; ref = {a}; }; // ref = {a} が引き継がれる model = p0; 複数のデータモデルを合成する際に同一のプロパティ参照が複数含まれている場合、スタブでないプロパティ参照が2つ以上存在すると曖昧となりエラーになります(または、すべてがスタブの場合もエラーになります)。 この場合、合成先のモデルでプロパティ参照を定義し直す必要があります。 .. code-block:: dmdl p0 = { a : INT; ref = {a}; }; p1 = { b : INT; ref = {b}; }; m = p0 + p1 + { ref = {a, b}; }; または、特殊な記法として ``<参照名> = <データモデル名>.<参照名>;`` と記述することで、合成元の参照を明示的に指定できます。 .. code-block:: dmdl p0 = { a : INT; ref = {a}; }; p1 = { a : INT; ref = {a}; }; m = p0 + p1 + { ref = p0.ref; }; いずれの場合においても、合成元のすべての参照と、合成左記の参照が同じ型(リスト/マップ、要素の型)でなければなりません。 DMDLコンパイラプラグインの利用 ============================== DMDLコンパイラはプラグインの仕組みを備えており、DMDLの解析やデータモデルプログラムの生成などをある程度制御できるようになっています。 プラグインを利用するには、DMDLコンパイラの起動オプション ``-plugin`` にプラグインのJARファイルを指定します。 組み込みプラグイン ------------------ DMDLコンパイラには、標準で様々なプラグインが組み込まれています。 以下は、主な組み込みプラグインの一覧です。 * `データモデルの名前空間`_ を指定する * `自動射影`_ を行う * ``Writable`` インターフェースを実装する * ``TEXT`` 型のプロパティに ``...AsString`` のメソッドを提供する * ``hashCode``, ``equals``, ``toString`` などの標準的なメソッドを実装 これらは、DMDLコンパイラの起動オプションを指定しなくても自動的に適用されます。 Direct I/Oとの連携 ------------------ Direct I/Oと連携したバッチアプリケーションでは、Direct I/Oが提供する特別な `データモデルの属性`_ を利用可能です。 詳しくは :doc:`../directio/index` を参照してください。 WindGateとの連携 ---------------- WindGateと連携したバッチアプリケーションでは、WindGateが提供する特別な `データモデルの属性`_ を利用可能です。 詳しくは :doc:`../windgate/index` を参照してください。 DMDLコンパイラプラグインの開発 ------------------------------ 詳しくは :doc:`developer-guide` を参照して下さい。