This is a cache of http://dbflute.seasar.org/ja/manual/reference/dfprop/schemapolicy/index.html. It is a snapshot of the page at 2024-11-13T00:06:04.062+0000.
schemaPolicyMap | DBFlute

schemaPolicyMap

SchemaPolicyCheck で利用する schemaPolicyMap.dfprop に関するページです。

このページは、DBFlute-1.1.2 以降を前提としています。 (1.1.1 は機能が少ないため、SchemaPolicyCheckをしっかり使うなら 1.1.2 以降へのアップグレードをオススメします)

schemaPolicyMapとは?

SchemaPolicyCheck のためのポリシーを設定する dfprop です(@since 1.1.1)

チェックのタイミング

この dfprop ファイルに設定が追加されると、Docタスクの最後に SchemaPolicyCheck が実行されます。 自動生成をしていれば、自然とチェックがかかるようになっています。

また、replaceSchemaMap.dfprop の isCheckSchemaPolicyInReps を true にすると、ReplaceSchema の DDL (CreateSchema) 実行直後に実行されます。 早い段階でチェックを検知するのに有効です。 (AdditionalSchemaのテーブルなど、ReplaceSchemaの時点ではチェックしづらいものは除外されますが、ほとんどのポリシーが実施されます)

チェックに引っかかったら?

Docタスクがエラーで終了します。チェック結果が例外メッセージに書いてあります。

例外メッセージ内のカテゴリ内訳です。

[Advice]
自然言語によるアドバイス
[Schema Policy]
定義されているすべてのポリシー
[Violation]
ポリシー違反の結果 (ここに注目!)
e.g. _FLGカラムのデータ型は BOOLEAN のはずなのに、INTEGERだったとき @Console
org.dbflute.exception.DfSchemaPolicyCheckViolationException: Look! Read the message below.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
The schema policy has been violated.

[Advice]
Make sure your violating schema (ERD and DDL).
And after that, execute renewal (or regenerate) again.
(tips: The schema policy is on schemaPolicyMap.dfprop)

[Schema Policy]
tableExceptList: []
tableTargetList: []
columnExceptMap: {}
isMainSchemaOnly: false
wholeMap: {themeList=[uniqueTableAlias, sameColumnAliasIfSameColumnName, sameColumnDbTypeIfSameColumnName, sameColumnSizeIfSameColumnName, sameColumnNameIfSameColumnAlias]}
tableMap:
  themeList: [hasPK, upperCaseBasis, identityIfPureIDPK]
  statementList:
    if tableName is $$ALL$$ then fkName is prefix:FK_$$table$$
columnMap:
  themeList: [upperCaseBasis]
  statementList:
    if columnName is suffix:_FLAG then bad
    if columnName is suffix:_FLG then notnull
    if columnName is suffix:_FLG then dbType is BOOLEAN
    if columnName is suffix:_FLG then classification

[Violation]
column.statement: if columnName is suffix:_FLG then dbType is BOOLEAN
 |-but INTEGER: (会員ログイン)MEMBER_LOGIN.(モバイルログインフラグ)MOBILE_LOGIN_FLG INTEGER(10) (Notnull)
 |-but INTEGER: (購入)PURCHASE.(支払完了フラグ)PAYMENT_COMPLETE_FLG INTEGER(10) (Notnull)
 +-but INTEGER: (サービスランク)SERVICE_RANK.(新規受け入れ可能フラグ)NEW_ACCEPTABLE_FLG INTEGER(10) (Notnull)
* * * * * * * * * */

プロパティ

map型プロパティ で、JDBC型とプログラム型の関連を key-value 形式で定義します。

schemaPolicyMapの仕様 @schemaPolicyMap.dfprop
map:{
    ; tableExceptList = list:{ [table-hints for exccept] }
    ; tableTargetList = list:{ [table-hints for target] }
    ; columnExceptMap = map:{
        ; [table-hint] = list:{ [column-hints for exccept] }
    }
    ; isMainSchemaOnly = [true or false]

    ; wholeMap = map:{
        ; themeList = list:{ [themes] }
    }
    ; tableMap = map:{
        ; themeList = list:{ [themes] }
        ; statementList = list:{ [statements] }
    }
    ; columnMap = map:{
        ; themeList = list:{ [themes] }
        ; statementList = list:{ [statements] }
    }
}

theme は、DBFlute側が提供するお決まりのパターンポリシーです。例えば、tableMap にて upperCaseBasis とすれば、テーブル名は大文字であることがチェックされます。

statement は、アプリ側が独自に設定するポリシーです。"もし...だったら、これは...である" というような形式で指定します。

e.g. カラム名が _FLG で終わっていたら、データ型は INTEGER であること @schemaPolicyMap.dfprop
map:{
    ...
    ; columnMap = map:{
        ; themeList = list:{ ... }
        ; statementList = list:{
            ; if columnName is suffix:_FLG then dbType is INTEGER
        }
    }
}

以下、(*)の付いたプロパティは必須です。

tableExceptList

チェックの除外テーブルのリスト。

値候補
テーブル名のlist型プロパティ
デフォルト
なし (除外するものなし)
補足
  • tableTargetList の指定がされている場合は無効 (target優先)
  • 前方一致: "prefix:前方一致させる文字列" という形式で指定
  • 後方一致: "suffix:後方一致させる文字列" という形式で指定
  • 部分一致: "contain:部分一致させる文字列" という形式で指定
  • 正規表現: "pattern:マッチさせる正規表現文字列" という形式で指定
  • 正規表現を除き、大文字小文字の区別なし (ただし実体と合わせることを推奨)
  • 複数指定時は、and 条件として扱われる (e.g. Aでもない、Bでもない)

基本的な使い方は、databaseInfoMap.dfprop の tableExceptList と似ています。

tableTargetList

チェックの対象テーブルのリスト。(特に指定がなければ全テーブルが対象)

値候補
テーブル名のlist型プロパティ
デフォルト
なし (全テーブルが対象)
補足
  • 指定方法は、基本的に tableExceptList と同じ
  • 複数指定時は、and 条件として扱われる (A もしくは B)

基本的な使い方は、databaseInfoMap.dfprop の tableTargetList と似ています。

columnExcecptMap

チェックの除外カラムのリスト。(テーブル名とカラム名で指定なのでmap)

値候補
テーブル名とカラム名のmap型プロパティ
デフォルト
なし (全てのカラムが対象)
補足
  • テーブル名の指定では、tableExceptList のように prefix: などが使える
  • カラム名リストの指定方法は、基本的に tableExceptList と同じ

基本的な使い方は、databaseInfoMap.dfprop の columnExcecptMap と似ていますが、若干違う部分があります。 例えば、テーブル名での prefix: などの利用可否が違います(@now 1.1.2)

isMainSchemaOnly

チェックの対象が、メインスキーマだけかどうか? (AdditionalSchemaを除外するかどうか?)

値候補
テーブル名とカラム名のmap型プロパティ
デフォルト
なし (全てのカラムが対象)
補足
  • テーブル名の指定では、tableExceptList のように prefix: などが使える
  • カラム名リストの指定方法は、基本的に tableExceptList と同じ

AdditionalSchema のテーブルも一緒にチェックされます。 もし、スキーマごとにポリシーが違うとチェックがやりづらいので、メインスキーマだけに絞ることができます。

それぞれの AdditionalSchema に独自のポリシーを設定することはできないため、 AdditionalSchema のテーブルのポリシーチェックは、別途そのスキーマ専用のDBFluteクライアントを用意すると良いでしょう。

wholeMap

スキーマ全体に対するポリシー。themeList だけが利用できます。(statementListは不可)

e.g. テーブルの別名がユニーク、カラム名が同じならカラムの別名も同じ @schemaPolicyMap.dfprop
map:{
    ...
    ; wholeMap = map:{
        ; themeList = list:{ uniqueTableAlias ; sameColumnAliasIfSameColumnName }
    }
    ...
}

tableMap

テーブルに対するポリシー。

e.g. テーブルに対するポリシー、別名がユニークとか、FKの名前がFK_とか @schemaPolicyMap.dfprop
map:{
    ...
    ; tableMap = map:{
        ; themeList = list:{ hasPK ; upperCaseBasis ; identityIfPureIDPK }
        ; statementList = list:{
            ; if tableName is $$ALL$$ then fkName is prefix:FK_$$table$$
        }
    }
    ...
}

columnMap

カラムに対するポリシー。

e.g. カラムに対するポリシー、大文字とか、_FLG は Notnull とか @schemaPolicyMap.dfprop
map:{
    ...
    ; columnMap = map:{
        ; themeList = list:{ upperCaseBasis }
        ; statementList = list:{
            ; if columnName is suffix:_FLG then notnull
        }
    }
    ...
}

wholeMap.themeList

利用できる theme は以下の通りです。

uniqueTableAlias
テーブルの別名がユニークである
sameColumnAliasIfSameColumnName
カラム名が同じならカラムの別名も同じ
sameColumnDbTypeIfSameColumnName
カラム名が同じならカラムのデータ型も同じ
sameColumnSizeIfSameColumnName
カラム名が同じならカラムのサイズも同じ
sameColumnNameIfSameColumnAlias
カラムの別名が同じならカラム名も同じ

別名を使う theme について、そもそも別名が定義されていないテーブルやカラムは比較対象になりません。 別名の必須チェックなどは、別途 tableMap や columnMap の statement にて表現すると良いでしょう。

wholeMap.statementList

wholeMap で statementList は利用できません。

tableMap.themeList

利用できる theme は以下の通りです。

hasPK
全てのテーブルがPKを持っている
upperCaseBasis
テーブル名は大文字 (SQL上の名前で判定)
lowerCaseBasis
テーブル名は小文字 (SQL上の名前で判定)
identityIfPureIDPK
FKではない ID で終わる単一PKカラムにはIdentityが付与される
sequenceIfPureIDPK
FKではない ID で終わる単一PKカラムにはsequenceが付与される
hasCommonColumn
共通カラムを持っている
hasAlias
別名がある (DBコメントの一部を別名として認識する設定が前提)
hasComment
コメントがある (別名部分を除く)

upperCaseBasis, lowerCaseBasis の大文字小文字判定では、DBFluteが管理するSQL上のテーブル名 (ConditionBeanのSQLで利用) の大文字小文字ルールを利用します。例えば、upperCaseBasis をポリシーにしたとき、DBMSのメタデータが小文字であっても、littleAdjustmentMap.dfprop にて isTableSqlNameUpperCase が true に設定されていればセーフです。

identityIfPureIDPK は、Sequence では効果ありません。 また、テーブル除外設定はできないので、除外したいテーブルがある場合は statement の方で実現します。

sequenceIfPureIDPK は、DBFluteとしてでテーブルとシーケンスが紐付いているかどうかをチェックします。 (sequenceMap.dfpropで紐付けるか、自動で紐付くPostgreSQLのserial型か)

hasCommonColumn は、共通カラムのすべてのカラムを持っていればOKです。

hasAlias は、documentMap.dfprop の aliasDelimiterInDbComment が設定されていることが前提です。 (DBFluteには、DBコメントの中の一部文字列を別名として扱う機能があります)

hasComment は、別名設定がされていれば、DBコメントから別名の除いた部分だけで比較されます。

tableMap.statementList

if の主語 (of table)

利用できる statement の if の主語は以下の通りです。

tableName
テーブル名 ($$変数$$あり)
alias
テーブルの別名(和名) ($$変数$$あり)
firstDate
テーブルの登録日(*A) e.g. if firstDate is after:2018/05/03 @since 1.1.8
pk_columnName
PKのカラム名 e.g. if pk_columnName is prefix:SEA_ @since 1.1.9
pk_dbType
PKのデータ型 e.g. if pk_dbType is CHAR
pk_size
PKのデータサイズ、小数点はカンマ空白(*B) e.g. if pk_size is 3
pk_dbType_with_size
PKのデータ型サイズ付き e.g. if pk_dbType_with_size is CHAR(3)

(*A): HistoryHTMLのテーブル追加履歴から判断。履歴が存在しないものは未来の日付として扱われ、after: ですべてヒットする。 運用途中から "これから追加されるテーブルだけにチェックをかける" というような使い方を想定しているので、利用方法は限定されている。 例えば、"before:" や "is not" は使えない。

(*B): 例えば、decimal型とかであれば、"8, 3" となる e.g. pk_size is 8, 3

if の $$変数$$ (of table)

then の中で $$変数$$ と書くことで、その値を利用可能 (e.g. $$comment$$はコメント):

$$table$$
$$tableName$$ と同じ @since 1.1.9
$$tableName$$
alias にて利用可能 @since 1.1.9
$$comment$$
tableName, alias にて利用可能 @since 1.1.9

※逆に、$$定義されていない名前$$ が指定されていた場合はエラーになります。@since 1.1.9

then の "isなし" 表現 (of table)

利用できる statement の then の isなし 表現は以下の通りです。

bad
もうそれダメ e.g. if ... is ... then bad
hasPK
PKを持っているはず e.g. ... then hasPK @since 1.1.8
upperCaseBasis
テーブル名が大文字 e.g. ... then upperCaseBasis @since 1.1.8
lowerCaseBasis
テーブル名が小文字 e.g. ... then lowerCaseBasis @since 1.1.8
identityIfPureIDPK
FKでない ID で終わる単一PKならIdentityが付与される @since 1.1.8
sequenceIfPureIDPK
FKでない ID で終わる単一PKならSequenceが付与される @since 1.1.9
hasCommonColumn
共通カラムを持っているはず e.g. ... then hasCommonColumn
hasAlias
別名がある e.g. ... then hasAlias @since 1.1.8
hasComment
コメントがある (別名部分を除く) e.g. ... then hasComment @since 1.1.8

then の "isあり" 表現 (of table)

利用できる statement の then の isあり 表現は以下の通りです。

tableName
テーブル名 ($$変数$$あり)
alias
テーブルの別名(和名) ($$変数$$あり)
comment
テーブルのDBコメント(別名抜き) e.g. then comment is contain:sea
pkName
PK制約の名前 e.g. then pkName is prefix:PK_ ($$変数$$あり)
fkName
FK制約の名前 e.g. then fkName is prefix:FK_ ($$変数$$あり)
uniqueName
UQ制約の名前 e.g. then uniqueName is prefix:UQ_ ($$変数$$あり)
indexName
インデックの名前 e.g. then indexName is prefix:IX_ ($$変数$$あり)
pk_columnName
PKのカラム名 e.g. then pk_columnName is suffix:_CODE
pk_dbType
PKのデータ型 e.g. then pk_dbType is CHAR
pk_size
PKのデータサイズ、小数点はカンマ空白(*A) e.g. then pk_size is 3
pk_dbType_with_size
PKのデータ型サイズ付き e.g. then pk_dbType_with_size is CHAR(3)
  • (*A): 例えば、decimal型とかであれば、"8, 3" となる e.g. pk_size is 8, 3

then の $$変数$$ (of table)

then の中で $$変数$$ と書くことで、その値を利用可能 (e.g. $$table$$はテーブル名):

$$table$$
$$tableName$$ とまったく同じ
$$tableName$$
pkName, fkName, uniqueName, indexName, alias にて利用可能 @since 1.1.9
$$first_columnName$$
pkName, fkName, uniqueName, indexName にて利用可能 @since 1.2.3
$$comment$$
tableName, alias にて利用可能 @since 1.1.9

※逆に、$$定義されていない名前$$ が指定されていた場合はエラーになります。@since 1.1.9

否定表現 (not) (of table)

notが使えるパターンは以下の通りです。

if の is not
e.g. if tableName is not prefix:CLS_ then ...
then の not ...
e.g. if ... then not hasCommonColumn
then の is not
e.g. if ... then pkName is not prefix:KP_

かつ、もしくは (and/or) (of table)

大きく二つに分かれます。

文章の連結
e.g. if tableName is prefix:CLS_ and pk_dbType is CHAR then ...
値の連結
e.g. if tableName is prefix:CLS_ and suffix:_STATUS then ...
  • 文章の連結と値の連結を組み合わせて使うこともできる
  • 文章の連結の中で、and と or を混ぜて使うことはできない (and なら全部 and)
  • 値の連結の中で、and と or を混ぜて使うことはできない (and なら全部 and)
  • 文章の連結は and で、値の連結は or とかは大丈夫 (逆も同じ)

not と and/or の組み合わせ (of table)

文章の連結の場合は、特にそれぞれの文章で独立した not になるので、特に迷うことはないでしょう。

値の連結 の and/or と not の組み合わせた場合は、is not (連結条件) というように、括弧 "()" で囲われているようなイメージで、連結条件だけで先に評価された後に not の評価がされます。

例えば、"is not SEA and LAND"
(SEAかつLANDにヒットするもの) ではないもの となる。
SEAかつLANDというものは存在し得ないので、"絶対に0件ヒットになるの逆" となり全件ヒットになるので、この表現は意味がない。 prefix:, suffix:, contain: を複合的に使って絞り込むようにヒットさせたもの、ではないものをヒットさせるのが通常の使い方となる。
"is not prefix:SEA_ and suffix:_LAND"
(SEA_で始まり、かつ、_LANDで終わるもの) ではないもの
"is not contain:SEA and contain:_LAND"
(SEAを含み、かつ、LANDも含むもの) ではないもの
例えば、"is not SEA or LAND"
(SEAもしくはLANDにヒットするもの) ではないもの となる。
この場合、SEAとLANDを単純に除外したと言える。よく使われる想定のパターンである。
"is not prefix:SEA_ or prefix:_LAND"
(SEA_で始まる、もしくは、LAND_で終わるもの) ではないもの
"is not contain:SEA or contain:LAND"
(SEAを含み、もしくは、LANDも含むもの) ではないもの

補足コメント (期待値など) (of table)

期待値などの補足を、statement自体に含めてコメントすることができます。すると、エラーになったときに一緒に表示されます。 (普通のdfpropのコメントだと、エラーでは表示されない)

then の後に続いて "=>" を付けて、その右側に自然言語でコメントを書きます。

e.g. statementの補足コメント @schemaPolicyMap.dfprop
map:{
    ...
    ; tableMap = map:{
        ; statementList = list:{
            ; if tableName is suffix:_ID then bad => カラムっぽいテーブル名ダメ
        }
    }
    ...
}

columnMap.themeList

利用できる theme は以下の通りです。

upperCaseBasis
カラム名は大文字 (SQL上の名前で判定)
lowerCaseBasis
カラム名は小文字 (SQL上の名前で判定)
hasAlias
別名がある (DBコメントの一部を別名として認識する設定が前提)
hasComment
コメントがある (別名部分を除く)

(tableMapの方とほぼ同じ) upperCaseBasis, lowerCaseBasis の大文字小文字判定では、DBFluteが管理するSQL上のカラム名 (ConditionBeanのSQLで利用) の大文字小文字ルールを利用します。例えば、upperCaseBasis をポリシーにしたとき、DBMSのメタデータが小文字であっても、littleAdjustmentMap.dfprop にて isColumnSqlNameUpperCase が true に設定されていればセーフです。

(tableMapの方とほぼ同じ) hasAlias は、documentMap.dfprop の aliasDelimiterInDbComment が設定されていることが前提です。 (DBFluteには、DBコメントの中の一部文字列を別名として扱う機能があります)

(tableMapの方とほぼ同じ) hasComment は、別名設定がされていれば、DBコメントから別名の除いた部分だけで比較されます。

column's statementList

if の主語 (of column)

利用できる statement の if の主語は以下の通りです。

tableName
テーブル名 e.g. if tableName is prefix:CLS_
column
カラムの特性(*後述) e.g. if column is notnull
columnName
カラム名 ($$変数$$あり)
tableColumnName
テーブルカラム名(*A) ($$変数$$あり)
alias
カラムの別名 ($$変数$$あり)
dbType
カラムのデータ型 e.g. if dbType is CHAR
size
カラムのデータサイズ、小数点はカンマ空白(*B) e.g. if size is 3
dbType_with_size
カラムのデータ型サイズ付き e.g. if dbType_with_size is CHAR(3)
firstDate
カラムの登録日(*C) e.g. if firstDate is after:2018/05/03 @since 1.1.8

(*A): テーブル名とカラム名をドットつないだ名前 e.g. MEMBER.MEMBER_NAME

(*B): 例えば、decimal型とかであれば、"8, 3" となる e.g. pk_size is 8, 3

(*C): HistoryHTMLのテーブル追加履歴から判断。履歴が存在しないものは未来の日付として扱われ、after: ですべてヒットする。 運用途中から "これから追加されるカラムだけにチェックをかける" というような使い方を想定しているので、利用方法は限定されている。 例えば、"before:" や "is not" は使えない。テーブル追加時に最初から存在するカラムは、テーブルの登録日が利用される。

if の $$変数$$ (of column)

if の中で $$変数$$ と書くことで、その値を利用できます。(e.g. $$table$$はテーブル名)

$$table$$
kとまったく同じ @since 1.1.8
$$tableName$$
columnName, tableColumnName にて利用可能 @since 1.1.9
$$tableAlias$$
alias にて利用可能 @since 1.1.8
$$comment$$
columnName, tableColumnName, alias にて利用可能 @since 1.1.9
$$column$$
$$columnName$$とまったく同じ @since 1.1.9
$$columnName$$
alias にて利用可能 @since 1.1.9

※逆に、$$定義されていない名前$$ が指定されていた場合はエラーになります。@since 1.1.9

then の "isなし" 表現 (of column)

利用できる statement の then の isなし 表現の "基本的なもの" は以下の通りです。

notnull
Notnull制約 e.g. then notnull
identity
identityカラム(連番) e.g. then identity
pk
PK制約 e.g. then pk
singlePK
単一カラムのPK制約 e.g. then singlePK @since 1.1.9
fk
FK制約 e.g. then fk
unique
UQ制約 e.g. then unique
index
インデックス e.g. then index
classification
区分値 e.g. then classification
upperCaseBasis
カラム名が大文字 e.g. then upperCaseBasis @since 1.1.8
lowerCaseBasis
カラム名が小文字 e.g. then lowerCaseBasis @since 1.1.8
hasAlias
別名がある e.g. then hasAlias @since 1.1.8
hasComment
コメントがある (別名部分を除く) e.g. then hasComment @since 1.1.8

加えて、他のテーブルのカラムと比較をするような横断的なものがあります。@since 1.1.8

sameColumnAliasIfSameColumnName
同じカラム名なら、別名は同じ @since 1.1.8
sameColumnDbTypeIfSameColumnName
同じカラム名なら、データ型は同じ @since 1.1.8
sameColumnSizeIfSameColumnName
同じカラム名なら、サイズは同じ @since 1.1.8
sameColumnNameIfSameColumnAlias
同じ別名なら、カラム名は同じ @since 1.1.8

この場合、比較対象の相手カラムに対しても、if で指定された条件で対象カラムかどうかの判定されます。

then の "isあり" 表現 (of column)

利用できる statement の then の isあり 表現は以下の通りです。

tableName
テーブル名 e.g. then tableName is prefix:CLS_
column
カラムの特性(*後述) e.g. then column is notnull
columnName
カラム名 ($$変数$$あり)
tableColumnName
テーブルカラム名(*B) ($$変数$$あり)
alias
カラムの別名 ($$変数$$あり)
dbType
カラムのデータ型 e.g. then dbType is CHAR
size
カラムのデータサイズ、小数点はカンマ空白(*C) e.g. then size is 3
dbType_with_size
カラムのデータ型サイズ付き e.g. then dbType_with_size is CHAR(3)
comment
カラムのDBコメント(別名抜き) e.g. then comment is contain:sea

(*B): テーブル名とカラム名をドットつないだ名前 e.g. MEMBER.MEMBER_NAME

(*C): 例えば、decimal型とかであれば、"8, 3" となる e.g. pk_size is 8, 3

then の $$変数$$ (of column)

then の中で $$変数$$ と書くことで、その値を利用できます。(e.g. $$table$$はテーブル名)

$$table$$
$$tableName$$ とまったく同じ @since 1.1.8
$$tableName$$
columnName, tableColumnName にて利用可能 @since 1.1.9
$$tableAlias$$
alias にて利用可能 @since 1.1.8
$$comment$$
columnName, tableColumnName, alias にて利用可能 @since 1.1.9
$$column$$
$$columnName$$とまったく同じ @since 1.1.9
$$columnName$$
alias にて利用可能 @since 1.1.9

※逆に、$$定義されていない名前$$ が指定されていた場合はエラーになります。@since 1.1.9

カラムの特性 (column is) (of column)

if column is ... や then ... や then column is ... で使える表現は以下の通りです。

notnull
Notnull制約 e.g. if column is notnull
identity
identityカラム(連番) e.g. if column is identity
pk
PK制約 e.g. if column is pk
singlePK
単一カラムのPK制約 e.g. then singlePK @since 1.1.9
fk
FK制約 e.g. if column is fk
unique
UQ制約 e.g. if column is unique
index
インデックス e.g. if column is index
classification
区分値 e.g. if column is classification

否定表現 (not) (of column)

tableMapの方とまったく同じです。

かつ、もしくは (and/or) (of column)

tableMapの方とまったく同じです。

not と and/or の組み合わせ (of column)

tableMapの方とまったく同じです。

補足コメント (期待値など) (of column)

tableMapの方とまったく同じです。

運用途中からの導入

これから追加するテーブルやカラムだけチェック

運用途中から SchemaPolicyCheck を導入する場合、"既存のテーブルはなかなか修正できないけど、これから追加するテーブルはチェックしたい" ということになります。

そこで、statement の if で利用できる firstDate を使うと良いでしょう。 指定された日付以降に追加されたテーブルやカラムはチェックする という条件が書けます。

e.g. firstDateを使って、これから追加されるテーブルだけチェック @schemaPolicyMap.dfprop
# 2018/05/04より未来に追加されたテーブルは、FK制約名は FK_[テーブル名] で始まること
; if firstDate is after:2018/05/04 then fkName is prefix:FK_$$table$$

一部のテーブルだけピンポイントで除外する

どうしても直せない一部のテーブルは、tableExceptListで完全に除外してしまうか、statement の if で除外してしまうと良いでしょう。 できるだけ後者で実現する方が他のチェックが掛かるので望ましいですが、あまりに複雑になってしまうと良くないので数が少なければ割り切って前者でも良いでしょう。

(themeListの) theme は絞り込み条件が書けませんが、同じチェックが statement の then の theme で指定できるものもあるので、statement方式に移行することで一部のものだけ除外を実現できます。と良いでしょう。

Example

シンプルなポリシーのExample

e.g. シンプルなポリシー @schemaPolicyMap.dfprop
map:{
    ...

    ; wholeMap = map:{
        ; themeList = list:{ uniqueTableAlias ; sameColumnAliasIfSameColumnName }
    }
    ; tableMap = map:{
        ; themeList = list:{ hasPK ; upperCaseBasis ; identityIfPureIDPK }
        ; statementList = list:{
            ; if tableName is $$ALL$$ then fkName is prefix:FK_$$table$$
        }
    }
    ; columnMap = map:{
        ; themeList = list:{ upperCaseBasis }
        ; statementList = list:{
            ; if columnName is suffix:_FLAG then bad
            ; if columnName is suffix:_FLG then notnull
            ; if columnName is suffix:_FLG then dbType is INTEGER
            ; if columnName is suffix:_FLG then classification
        }
    }
}

ハイパーなポリシーのExample

かなり突っ込んだハイパーなポリシーのExampleです。

まるごとコピーしてから、現場にフィットするように修正しると良いでしょう。 ただし、いくつかの設定がMySQLに依存していますので、その部分は利用しているDBMSに合わせましょう。

e.g. ハイパーなポリシー @schemaPolicyMap.dfprop
map:{
    # ドキュメントへのリンクとか、dfpropに書いておくといいんじゃないかと
    # _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    # document is here:
    # http://dbflute.seasar.org/ja/manual/reference/dfprop/schemapolicy/
    # _/_/_/_/_/_/_/_/_/_/

    ; tableExceptList = list:{}
    ; tableTargetList = list:{}
    ; columnExceptMap = map:{}
    ; isMainSchemaOnly = false

    ; wholeMap = map:{
        ; themeList = list:{
            ; uniqueTableAlias
            ; sameColumnAliasIfSameColumnName
            ; sameColumnDbTypeIfSameColumnName
            ; sameColumnSizeIfSameColumnName
            ; sameColumnNameIfSameColumnAlias
        }
    }

    ; tableMap = map:{
        ; themeList = list:{
            ; hasPK
            ; hasAlias
            ; hasComment
            ; upperCaseBasis
            ; identityIfPureIDPK
        }
        ; statementList = list:{
            ## 共通カラム ##
            # もし、"区分値テーブルは共通カラムがない" とかであれば、ALLじゃなくてprefixなどで絞り込み
            ; if tableName is $$ALL$$ then hasCommonColumn => 区分値のテーブルも含めて共通カラムは必須

            ## 制約 (e.g. PK, FK) ##
            # _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
            # 例えば FK なら、FK_[テーブル名]_[FKカラム名 or 相手のテーブル名]
            ; if tableName is $$ALL$$ then fkName is prefix:FK_$$table$$

            # MySQL では FK も INDEX に含まれるため、INDEX名も同様のチェックが必要
            ; if tableName is $$ALL$$ then indexName is prefix:IX_$$table$$ or prefix:FK_$$table$$

            # ERDツールによっては、PK制約名を付けづらいケースもあるかも (なら諦めるもアリ)
            ; if tableName is $$ALL$$ then pkName is prefix:PK_$$table$$

            # UQ制約名の付け方は、色々なパターンがありそう
            ; if tableName is $$ALL$$ then uniqueName is prefix:UQ_$$table$$
            # _/_/_/_/_/_/_/_/_/_/

            ## 区分値テーブル ##
            # CLS_で始まるテーブルを区分値テーブルとしていることが前提。
            # コード値をchar(3)だけにするか、色々なサイズも許すか、それによってチェックするかしないかも変わりそう。
            # 限定できるなら、char(2) or char(3) というように or でつなげることもできる。
            ; if tableName is prefix:CLS_ then pk_dbType_with_size is char(3)

            ## コメント ##
            ; if alias is $$tableName$$ then bad => 論理名がテーブル名と同じじゃダメ
            ; if alias is $$comment$$ then bad => コメントが論理名と同じじゃダメ
            ; if tableName is $$comment$$ then bad => コメントがテーブル名と同じじゃダメ
        }
    }
    ; columnMap = map:{
        ; themeList = list:{
            ; hasAlias
            # 全カラムコメント必須はさすがにつらいと思うのでコメントアウト。
            # いやいや、コメントは必ず入れよう!というのであれば、ぜひコメントアウト解除で!
            #; hasComment
            ; upperCaseBasis
        }
        ; statementList = list:{
            ## IDカラム ##
            # _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
            ; if columnName is suffix:_ID then alias is pattern:.+ID(\(.+\))?$ => IDカラムなら論理名は "なんとかID" にしよう
            ; if columnName is not suffix:_ID then alias is not suffix:ID => IDカラムじゃないのに、"なんとかID" という論理名なの?

            # IDカラムを数値だけにするか、文字列もOKか、現場によってポリシー変わりそう
            ; if columnName is suffix:_ID then dbType is bigint or int or bigint unsigned or int unsigned => IDカラムは数値で!

            ; if columnName is $$table$$_ID then alias is $$tableAlias$$ID => カラム名が[テーブル名]_IDなのであれば、論理名も[テーブル論理名ID]にしよう
            ; if alias is $$tableAlias$$ID then columnName is $$table$$_ID => 論理名が[テーブル論理名ID]なのであれば、カラム名も[テーブル名]_IDにしよう
            # _/_/_/_/_/_/_/_/_/_/

            ## NOカラム ##
            ; if columnName is suffix:_NO then alias is suffix:番号 or suffix:NO => NOカラムなら論理名は "なんとか番号" とか "なんとかNO" にしよう
            ; if columnName is not suffix:_NO then alias is not suffix:番号 and not suffix:NO => NOカラムじゃないのに、"なんとか番号" とか "なんとかNO" という論理名なの?

            ## CODEカラム ##
            ; if columnName is suffix:_CODE then alias is suffix:コード => CODEカラムなら論理名は "なんとかコード" にしよう
            ; if columnName is not suffix:_CODE then alias is not suffix:コード => CODEカラムじゃないのに、"なんとかコード" という論理名なの?
            ; if tableName is prefix:CLS_ and column is pk then classification => 区分値テーブルだったら、PKは区分値カラムのはず (dfpropを確認しよう)
            ; if columnName is suffix:_CD then bad => _CODE に統一

            ## FLGカラム ##
            # _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
            ; if columnName is suffix:_FLG then alias is suffix:フラグ => FLGカラムなら論理名は "なんとかフラグ" にしよう
            ; if columnName is not suffix:_FLG then alias is not suffix:フラグ => FLGカラムじゃないのに、"なんとかフラグ" という論理名なの?

            # MySQLのメタデータとしては、boolean は bit になる
            ; if columnName is suffix:_FLG then dbType is bit

            ; if columnName is suffix:_FLG then column is notnull => nullのフラグはやめよー
            ; if columnName is suffix:_FLAG then bad => _FLG に統一
            # _/_/_/_/_/_/_/_/_/_/

            ## DATEカラム ##
            ; if columnName is suffix:_DATE then alias is suffix:日 => DATEカラム(時分秒のない日付)なら論理名は "なんとか日" にしよう
            ; if columnName is not suffix:_DATE then alias is not suffix:日 => DATEカラム(時分秒のない日付)じゃないのに、"なんとか日" という論理名なの?
            ; if columnName is suffix:_DATE then dbType is date => なんとか_DATEなら、日付ということで date に

            ## DATETIMEカラム ##
            ; if columnName is suffix:_DATETIME then alias is suffix:日時 => DATETIMEカラムなら論理名は "なんとか日時" にしよう
            ; if columnName is not suffix:_DATETIME then alias is not suffix:日時 => DATETIMEカラムじゃないのに、"なんとか日時" という論理名なの?
            ; if columnName is suffix:_DATETIME then dbType is datetime => なんとか_DATETIMEなら、日時ということで datetime に

            ## コメント ##
            ; if alias is $$columnName$$ and columnName is not pattern:(URL|UUID|CUID) then bad => 論理名がカラム名が同じなのはダメ。ただ、URLとかはしょうがないので not pattern に列挙
            ; if alias is $$comment$$ then bad => コメントが論理名と同じなのはダメ
            ; if columnName is $$comment$$ then bad => コメントがカラム名と同じなのはダメ

            # 区分値カラムの扱い方は、色々なパターンがありそう
            ; if columnName is suffix:_TYPE then bad => "_TYPE" で終わるカラム名なら、"_TYPE_CODE" にして区分値テーブルで表現しよう

            ## NGワード ##
            # 表記ゆれとか曖昧な表現とかをチェックしたいなら、ここで bad, bad
            ; if alias is contain:名称 then bad => 「名」で統一
            ; if alias is pattern:.*[^名]カナ.* then bad => 「カナ」は「名カナ」にしてください。
            ; if alias is pattern:(.*ユーザ[^ー].*|.*ユーザ) then bad => 「ユーザ」は、「ユーザー」で統一してください。
        }
    }
}

identityIfPureIDPK で除外テーブル

備え付けの theme は使わず、column.statement で細かく設定すればテーブル除外ありの identityIfPureIDPK を実現することができます。

e.g. identityIfPureIDPK をテーブル除外 @schemaPolicyMap.dfprop
map:{
    ...

    ; tableMap = map:{
        ; themeList = list:{
            # unused here, see check it by column.statement to except specified tables 
            #; identityIfPureIDPK
        }
        ; statementList = list:{
            ...
        }
    }
    ; columnMap = map:{
        ; themeList = list:{ upperCaseBasis }
        ; statementList = list:{
            # ID column
            ; if tableName is not prefix:MST_ and column is pk and columnName is suffix:_ID and column is not fk then identity => instead of identityIfPureIDPK

            ...
        }
    }
}