EntityMeta.java

package com.github.mygreen.sqlmapper.core.meta;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

import org.springframework.util.LinkedCaseInsensitiveMap;

import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

/**
 * エンティティのメタ情報です。
 *
 * @author T.TSUCHIE
 *
 */
@RequiredArgsConstructor
public class EntityMeta {

    /**
     * エンティティのクラスタイプです。
     */
    @Getter
    private final Class<?> entityType;

    /**
     * エンティティの名称です。SQL自動作成時のテーブルのエイリアス名などに使用されます。
     */
    @Getter
    @Setter
    private String name;

    @Getter
    @Setter
    private TableMeta tableMeta;

    /**
     * プロパティ情報
     * <p>key=プロパティ名</p>
     */
    private LinkedCaseInsensitiveMap<PropertyMeta> propertyMetaMap = new LinkedCaseInsensitiveMap<>();

    /**
     * 主キーのプロパティ情報
     */
    @Getter
    private List<PropertyMeta> idPropertyMetaList = new ArrayList<>();

    /**
     * バージョンキー用のカラムプロパティ
     */
    @Getter
    private Optional<PropertyMeta> versionPropertyMeta = Optional.empty();

    /**
     * 作成日時用のカラムプロパティ
     */
    @Getter
    private Optional<PropertyMeta> createdAtPropertyMeta = Optional.empty();

    /**
     * 作成者用のカラムプロパティ
     */
    @Getter
    private Optional<PropertyMeta> createdByPropertyMeta = Optional.empty();

    /**
     * 修正日時用のカラムプロパティ
     */
    @Getter
    private Optional<PropertyMeta> updatedAtPropertyMeta = Optional.empty();

    /**
     * 修正者用のカラムプロパティ
     */
    @Getter
    private Optional<PropertyMeta> updatedByPropertyMeta = Optional.empty();

    /**
     * カラム用のプロパティ情報
     * <p>key=カラム名</p>
     */
    private LinkedCaseInsensitiveMap<PropertyMeta> columnPropertyMetaMap = new LinkedCaseInsensitiveMap<>();

    /**
     * プロパティのメタ情報を追加します。
     * @param propertyMeta メタ情報
     */
    public void addPropertyMeta(@NonNull PropertyMeta propertyMeta) {

        this.propertyMetaMap.put(propertyMeta.getName(), propertyMeta);

        setupRoleProperty(propertyMeta);

        // 埋め込みプロパティの場合、子プロパティを追加する。
        if(propertyMeta.isEmbedded()) {
            propertyMeta.getEmbeddedablePopertyMetaList().forEach(p -> setupRoleProperty(p));
        }

    }

    /**
     * プロパティメタ情報を取得します。
     * @param propertyName プロパティ名
     * @return プロパティメタ情報
     */
    public Optional<PropertyMeta> getPropertyMeta(@NonNull String propertyName) {

        return Optional.ofNullable(propertyMetaMap.get(propertyName));

    }

    /**
     * プロパティ名を指定して、プロパティメタ情報を取得します。
     * 埋め込みID内のプロパティも抽出対象とします。
     *
     * @param propertyName プロパティ名
     * @return プロパティメタ情報
     */
    public Optional<PropertyMeta> findPropertyMeta(@NonNull String propertyName) {

        PropertyMeta foundPropertyMeta = propertyMetaMap.get(propertyName);
        if(foundPropertyMeta != null) {
            return Optional.of(foundPropertyMeta);
        }

        for(PropertyMeta propertyMeta : getAllPropertyMeta()) {
            if(propertyMeta.isEmbedded()) {
                for(PropertyMeta embeddedPropertyMeta : propertyMeta.getEmbeddedablePopertyMetaList()) {
                    if(embeddedPropertyMeta.getName().equals(propertyName)) {
                        return Optional.of(embeddedPropertyMeta);
                    }
                }
            }
        }

        return Optional.empty();


    }

    /**
     * 全てのプロパティメタ情報の一覧を返します。
     * @return プロパティメタ情報の一覧
     */
    public Collection<PropertyMeta> getAllPropertyMeta() {
        return propertyMetaMap.values();
    }

    /**
     * プロパティメタ情報のサイズを返します。
     * @return プロパティメタ情報のサイズ
     */
    public int getPropertyMetaSize() {
        return propertyMetaMap.size();
    }

    /**
     * プロパティメタデータがあるかどうかを返します。
     * @param propertyName プロパティ名
     * @return {@literal true}のときプロパティメタデータがあります。
     */
    public boolean hasPropertyMeta(String propertyName) {
        return propertyMetaMap.containsKey(propertyName);
    }

    /**
     * カラムに紐づくプロパティメタ情報を取得します。
     * @param columnName カラム名。大文字・小文字の区別はしない。
     * @return カラムに紐づくプロパティメタ情報
     */
    public Optional<PropertyMeta> getColumnPropertyMeta(@NonNull String columnName) {

        return Optional.ofNullable(columnPropertyMetaMap.get(columnName));
    }

    /**
     * カラムに紐づく全てのプロパティメタ情報を取得します。
     * @return カラムに紐づく全てのプロパティメタ情報
     */
    public Collection<PropertyMeta> getAllColumnPropertyMeta() {
        return columnPropertyMetaMap.values();
    }

    /**
     * カラムに結びつくプロパティメタデータがあるかどうかを返します。
     *
     * @param columnName カラム名
     * @return プロパティメタデータがあるかどうか
     */
    public boolean hasColumnPropertyMeta(String columnName) {
        return columnPropertyMetaMap.containsKey(columnName);
    }

    /**
     * 埋め込み用IDのプロパティメタ情報を取得します。
     * @return 埋め込み用IDのプロパティメタ情報
     */
    public Optional<PropertyMeta> getEmbeddedIdPropertyMeta() {
        return propertyMetaMap.values().stream()
                .filter(p -> p.isEmbedded())
                .findFirst();
    }

    /**
     * バージョンを表すプロパティメタデータを持つかどうか。
     * @return バージョンを表すプロパティメタデータがあれば {@literal true} を返します。
     */
    public boolean hasVersionPropertyMeta() {
        return versionPropertyMeta.isPresent();
    }

    /**
     * 作成日時を表すプロパティのメタデータを持つかどうか。
     * @return 作成日時を表すプロパティのメタデータがあれば {@literal true} を返す。
     */
    public boolean hasCreatedAtPropertyMeta() {
        return createdAtPropertyMeta.isPresent();
    }

    /**
     * 作成者を表すプロパティのメタデータを持つかどうか。
     * @return 作成者を表すプロパティのメタデータがあれば {@literal true} を返す。
     */
    public boolean hasCreatedByPropertyMeta() {
        return createdByPropertyMeta.isPresent();
    }

    /**
     * 更新日時を表すプロパティのメタデータを持つかどうか。
     * @return 修正日時を表すプロパティのメタデータがあれば {@literal true} を返す。
     */
    public boolean hasUpdatedAtPropertyMeta() {
        return updatedAtPropertyMeta.isPresent();
    }

    /**
     * 更新者を表すプロパティのメタデータを持つかどうか。
     * @return 修正者を表すプロパティのメタデータがあれば {@literal true} を返す。
     */
    public boolean hasUpdatedByPropertyMeta() {
        return updatedByPropertyMeta.isPresent();
    }

    /**
     * 役割を持つプロパティを設定する
     * @param propertyMeta 対象のプロパティメタ情報
     */
    private void setupRoleProperty(PropertyMeta propertyMeta) {

        if(propertyMeta.isTransient()) {
            return;
        }

        if(propertyMeta.isId()) {
            this.idPropertyMetaList.add(propertyMeta);
        }

        if(propertyMeta.isVersion()) {
            this.versionPropertyMeta = Optional.of(propertyMeta);
        }

        if(propertyMeta.isCreatedAt()) {
            this.createdAtPropertyMeta = Optional.of(propertyMeta);
        }

        if(propertyMeta.isCreatedBy()) {
            this.createdByPropertyMeta = Optional.of(propertyMeta);
        }

        if(propertyMeta.isUpdatedAt()) {
            this.updatedAtPropertyMeta = Optional.of(propertyMeta);
        }

        if(propertyMeta.isUpdatedBy()) {
            this.updatedByPropertyMeta = Optional.of(propertyMeta);
        }

        if(propertyMeta.getColumnMeta() != null) {
            this.columnPropertyMetaMap.put(propertyMeta.getColumnMeta().getName(), propertyMeta);
        }

    }
}