Claude-skill-registry database-adapter

データベースアダプター(PostgreSQL/MySQL両対応)の開発・修正を行う際に使用。SqlExecutorパターン、マイグレーション、DB固有SQL実装時に役立つ。

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/database-adapter" ~/.claude/skills/majiayu000-claude-skill-registry-database-adapter && rm -rf "$T"
manifest: skills/data/database-adapter/SKILL.md
source content

データベースアダプター開発ガイド

ドキュメント

  • libs/idp-server-database/README.md
    - データベース設計・マイグレーション
  • documentation/docs/content_10_ai_developer/ai-20-adapters.md
    - アダプター実装ガイド
  • documentation/docs/content_10_ai_developer/ai-21-core-adapter.md
    - Core Adapterガイド
  • documentation/docs/content_10_ai_developer/ai-22-database.md
    - データベースガイド

機能概要

データベースアダプターは、PostgreSQL/MySQL両方をサポートする永続化層。

  • 両DB対応: 全機能でPostgreSQL/MySQL両方実装必須
  • SqlExecutorパターン: DB固有SQLを抽象化
  • Flyway: マイグレーション管理
  • 読み書き分離:
    @Transaction
    /
    @Transaction(readOnly = true)
    アノテーション

モジュール構成

libs/
├── idp-server-core-adapter/                    # 永続化実装
│   └── .../adapters/datasource/
│       ├── audit/
│       │   ├── command/
│       │   │   ├── AuditLogSqlExecutor.java       # インターフェース
│       │   │   ├── AuditLogSqlExecutors.java      # ファクトリ
│       │   │   ├── PostgresqlExecutor.java        # PostgreSQL実装
│       │   │   └── MysqlExecutor.java             # MySQL実装
│       │   └── query/
│       │       └── (同様の構造)
│       ├── token/
│       ├── identity/
│       ├── authentication/
│       ├── ciba/
│       └── ...
│
├── idp-server-database/                        # マイグレーション
│   ├── postgresql/
│   │   ├── V0_9_0__init_lib.sql               # 初期スキーマ
│   │   └── V1_0_0__*.sql                      # バージョン別マイグレーション
│   └── mysql/
│       ├── V0_9_0__init_lib.mysql.sql         # ※ .mysql.sql 接尾辞
│       └── V0_9_21_1__*.mysql.sql
│
└── idp-server-platform/                        # 共通基盤
    └── .../datasource/
        ├── DatabaseType.java                   # POSTGRESQL, SPANNER, MYSQL
        ├── SqlExecutor.java                    # SQL実行ヘルパー
        └── TransactionManager.java             # トランザクション管理

SqlExecutor パターン

基本構造

AuditLogSqlExecutor.java
:

// 1. インターフェース定義(Tenant第一引数)
public interface AuditLogSqlExecutor {
    void insert(Tenant tenant, AuditLog auditLog);
}

PostgresqlExecutor.java
:

// 2. PostgreSQL実装
public class PostgresqlExecutor implements AuditLogSqlExecutor {
    @Override
    public void insert(Tenant tenant, AuditLog auditLog) {
        // SqlExecutorが内部でTransactionManager.getConnection()を使用
        SqlExecutor sqlExecutor = new SqlExecutor();
        String sqlTemplate = """
            INSERT INTO audit_log (
                id, type, description, tenant_id, client_id, user_id, ...
            ) VALUES (
                ?::uuid, ?, ?, ?::uuid, ...
            );
            """;
        List<Object> params = new ArrayList<>();
        params.add(auditLog.id().value());
        // ...
        sqlExecutor.execute(sqlTemplate, params);
    }
}

MysqlExecutor.java
:

// 3. MySQL実装
public class MysqlExecutor implements AuditLogSqlExecutor {
    @Override
    public void insert(Tenant tenant, AuditLog auditLog) {
        SqlExecutor sqlExecutor = new SqlExecutor();
        String sqlTemplate = """
            INSERT INTO audit_log (
                id, type, description, tenant_id, client_id, user_id, ...
            ) VALUES (
                ?, ?, ?, ?, ...
            );
            """;
        // MySQL固有: UUIDキャストなし
        // ...
    }
}

AuditLogSqlExecutors.java
:

// 4. ファクトリ(ディスパッチャー)
public class AuditLogSqlExecutors {
    Map<DatabaseType, AuditLogSqlExecutor> executors;

    public AuditLogSqlExecutors() {
        executors = new HashMap<>();
        executors.put(DatabaseType.POSTGRESQL, new PostgresqlExecutor());
        executors.put(DatabaseType.MYSQL, new MysqlExecutor());
    }

    public AuditLogSqlExecutor get(DatabaseType databaseType) {
        return executors.get(databaseType);
    }
}

読み書き分離

EntryServiceレイヤーで

@Transaction
アノテーションにより制御:

// 書き込み(Primary)
@Transaction
public class OAuthFlowEntryService { ... }

// 読み取り専用(Replica)
@Transaction(readOnly = true)
public class UserinfoEntryService { ... }

@Transaction(readOnly = true)
public class OidcMetaDataEntryService { ... }

PostgreSQL vs MySQL 差異

INSERT時の競合処理

操作PostgreSQLMySQL
UPSERT
ON CONFLICT (id) DO UPDATE SET ...
ON DUPLICATE KEY UPDATE ...
INSERT IGNORE
ON CONFLICT DO NOTHING
INSERT IGNORE INTO ...

UUID型

操作PostgreSQLMySQL
UUIDキャスト
?::uuid
?
(文字列として保存)

JSON操作

操作PostgreSQLMySQL
JSON型
jsonb
JSON
JSON抽出
column->>'key'
JSON_UNQUOTE(JSON_EXTRACT(column, '$.key'))
JSON検索
column @> '{"key": "value"}'
JSON_CONTAINS(column, '"value"', '$.key')

日時操作

操作PostgreSQLMySQL
現在時刻
NOW()
NOW()
タイムゾーン
AT TIME ZONE 'UTC'
CONVERT_TZ(..., '+00:00', 'UTC')
間隔
INTERVAL '1 day'
INTERVAL 1 DAY

マイグレーション

ファイル命名規則

PostgreSQL: V{major}_{minor}_{patch}__{description}.sql
MySQL:      V{major}_{minor}_{patch}__{description}.mysql.sql

例:
- postgresql/V1_2_0__add_user_status_column.sql
- mysql/V1_2_0__add_user_status_column.mysql.sql

注意: MySQLは

.mysql.sql
接尾辞が必須。

実行方法

# Docker経由(推奨)
docker compose up flyway-migrator

# 直接実行
./gradlew :libs:idp-server-database:flywayMigrate

両DB対応マイグレーション

PostgreSQL と MySQL で同じバージョン番号のファイルを作成:

libs/idp-server-database/
├── postgresql/
│   └── V1_2_0__add_user_status_column.sql
└── mysql/
    └── V1_2_0__add_user_status_column.mysql.sql

Command / Query 分離

構造パターン

datasource/{domain}/
├── command/                    # 書き込み操作
│   ├── {Domain}CommandSqlExecutor.java
│   ├── {Domain}CommandSqlExecutors.java
│   ├── PostgresqlExecutor.java
│   └── MysqlExecutor.java
└── query/                      # 読み取り操作
    ├── {Domain}QuerySqlExecutor.java
    ├── {Domain}QuerySqlExecutors.java
    ├── PostgresqlExecutor.java
    └── MysqlExecutor.java

DatabaseType

DatabaseType.java
:

public enum DatabaseType {
    POSTGRESQL,
    SPANNER,     // Google Cloud Spanner
    MYSQL;
}

コマンド

# ビルド
./gradlew :libs:idp-server-core-adapter:compileJava
./gradlew :libs:idp-server-database:build

# マイグレーション確認
./gradlew :libs:idp-server-database:flywayInfo

# テスト
./gradlew :libs:idp-server-core-adapter:test

チェックリスト

新規DataSource実装時:

  • SqlExecutor インターフェース作成(Tenant第一引数)
  • PostgresqlExecutor 実装
  • MysqlExecutor 実装
  • SqlExecutors ファクトリ作成
  • DataSource クラス作成
  • PostgreSQL マイグレーション追加(.sql)
  • MySQL マイグレーション追加(.mysql.sql)
  • 両DBでテスト実行

トラブルシューティング

SQL構文エラー

問題原因解決策
PostgreSQLで動くがMySQLでエラーDB固有構文の混在両Executor実装を確認
UUIDキャストエラー
?::uuid
がMySQLで失敗
MySQL版では文字列として扱う
JSONクエリ失敗JSON関数の差異上記JSON操作表を参照

マイグレーション失敗

問題原因解決策
MySQLでファイル認識されない接尾辞が
.sql
.mysql.sql
に変更
バージョン競合既存マイグレーションとの衝突
flyway repair
実行
スキーマ不整合手動変更との不一致
docker compose down -v
で初期化

関連スキル

スキル用途
/local-environment
ローカルDB環境構築
/architecture
アーキテクチャ全体像
/operations
運用・監視