{"id":35320415,"url":"https://github.com/y-ok/flexdblink","last_synced_at":"2026-04-06T00:08:50.951Z","repository":{"id":310206984,"uuid":"1039001463","full_name":"y-ok/FlexDBLink","owner":"y-ok","description":"Manage DB test data as text (CSV/JSON/YAML/XML ↔ DB), with LOB files and JUnit 5 + Spring integration for Oracle/PostgreSQL/MySQL/SQL Server.","archived":false,"fork":false,"pushed_at":"2026-03-01T12:09:42.000Z","size":1204,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-01T14:55:27.395Z","etag":null,"topics":["csv","dbunit","doma2","json","mybatis","mysql","oracle","postgresql","spring","spring-boot","sqlserver","xml","yaml"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/y-ok.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-08-16T09:08:02.000Z","updated_at":"2026-03-01T12:09:46.000Z","dependencies_parsed_at":"2025-09-03T00:15:00.727Z","dependency_job_id":"90bae3dc-feb1-425a-a578-2aa2dfd3264e","html_url":"https://github.com/y-ok/FlexDBLink","commit_stats":null,"previous_names":["y-ok/csvdblink","y-ok/flexdblink"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/y-ok/FlexDBLink","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/y-ok%2FFlexDBLink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/y-ok%2FFlexDBLink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/y-ok%2FFlexDBLink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/y-ok%2FFlexDBLink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/y-ok","download_url":"https://codeload.github.com/y-ok/FlexDBLink/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/y-ok%2FFlexDBLink/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29991312,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T01:47:34.672Z","status":"online","status_checked_at":"2026-03-02T02:00:07.342Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csv","dbunit","doma2","json","mybatis","mysql","oracle","postgresql","spring","spring-boot","sqlserver","xml","yaml"],"created_at":"2025-12-30T21:29:56.781Z","updated_at":"2026-04-06T00:08:50.944Z","avatar_url":"https://github.com/y-ok.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FlexDBLink\n\n[![GitHub release](https://img.shields.io/github/v/release/y-ok/FlexDBLink)](https://github.com/y-ok/FlexDBLink/releases)\n[![CI](https://github.com/y-ok/FlexDBLink/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/y-ok/FlexDBLink/actions/workflows/ci.yml)\n[![Coverage](https://codecov.io/gh/y-ok/FlexDBLink/branch/main/graph/badge.svg)](https://codecov.io/gh/y-ok/FlexDBLink)\n\n**FlexDBLink** is a data management tool that automates \"DB data preparation and verification\" in development and testing workflows.\n\nIt performs **bulk load/dump** between databases and text files such as CSV / JSON / YAML / XML.\nLOB data (BLOB/CLOB) can be intuitively managed via \"external file references.\"\nThe JUnit 5 extension automates per-test data setup and rollback, enabling **Git-based configuration management without writing any SQL scripts**.\n\n---\n\n## Why FlexDBLink?\n\n### Do any of these sound familiar?\n\n- Writing `INSERT` / `TRUNCATE` SQL by hand for every test\n- Missing DB cleanup steps before/after tests\n- LOB data (images, PDFs, XML) is hard to manage with plain SQL\n- DB state differs across development environments with no reproducibility\n- Want to version-control data in Git, but SQL diffs are hard to read\n\n### How FlexDBLink solves them\n\n| Problem | Solution |\n| --------- | ---------- |\n| Manual SQL for data management | Manage with text files: CSV/JSON/YAML/XML |\n| Difficulty handling LOB data | Reference external files with `file:filename` |\n| Manual DB cleanup before/after tests | Automatic load and rollback with `@LoadData` |\n| Non-reproducible DB state across environments | Version-control datasets in Git |\n| Load order management under FK constraints | Resolve FK dependencies automatically (no manual `table-ordering.txt` required) |\n\n---\n\n## Key Features\n\n- **Load \u0026 Dump** — Bidirectional data transfer between CSV / JSON / YAML / XML and databases\n- **LOB External File References** — Manage BLOB/CLOB by simply writing `file:xxx` in a CSV cell\n- **Two-phase Load** — Initial data (`pre`) + scenario-specific incremental data\n- **Automatic FK-based Load Ordering** — Resolves parent/child load order at runtime without manual ordering files\n- **JUnit 5 Extension** — Per-test data injection and automatic rollback via `@LoadData`\n- **Multi-DB Support** — Oracle / PostgreSQL / MySQL / SQL Server\n\n---\n\n## Requirements\n\n| Requirement | Details |\n| ------------- | --------- |\n| Java | 11 or higher (CI verified: core on **11 / 17 / 21 / 25**, plugin on **11**) |\n| OS | Windows / macOS / Linux |\n\n\u003e FlexDBLink does not bundle JDBC drivers. Add the driver for your target database in your project\n\u003e or plugin configuration.\n\n---\n\n## Quick Start\n\n### 1. Download\n\nDownload the latest `FlexDBLink-distribution.zip` from [GitHub Releases](https://github.com/y-ok/FlexDBLink/releases) and extract it.\n\n```bash\nFlexDBLink/\n  flexdblink.jar\n  conf/\n    application.yml    ← configuration file\n```\n\n### 2. Edit the Configuration File\n\nEdit `conf/application.yml` to set connection details and the data path.\n\n#### **Single DB**\n\n```yaml\ndata-path: /path/to/your/data\n\nconnections:\n  - id: DB1\n    url: jdbc:oracle:thin:@localhost:1521/OPEDB\n    user: oracle\n    password: password\n    driver-class: oracle.jdbc.OracleDriver\n```\n\n#### **Multiple DBs** (just add more entries under `connections`)\n\n```yaml\ndata-path: /path/to/your/data\n\nconnections:\n  - id: DB1\n    url: jdbc:oracle:thin:@localhost:1521/OPEDB\n    user: oracle\n    password: password\n    driver-class: oracle.jdbc.OracleDriver\n  - id: DB2\n    url: jdbc:postgresql://localhost:5432/mydb\n    user: postgres\n    password: password\n    driver-class: org.postgresql.Driver\n```\n\n\u003e Use `--target DB1,DB2` to restrict processing to specific DB IDs. When omitted, all connections are targeted.\n\u003e\n\u003e Dialect is resolved per connection entry. The tool checks `connections[].driver-class` first and\n\u003e falls back to the JDBC URL. Supported dialects: `ORACLE`, `POSTGRESQL`, `MYSQL`, `SQLSERVER`.\n\u003e If one connection cannot be resolved to a supported dialect, the tool fails with an error that\n\u003e includes the target connection ID.\n\n### 3. Place Your Dataset\n\nPlace CSV files under `data-path`. The filename corresponds to the table name.\n\n```bash\n/path/to/your/data/\n  load/\n    pre/\n      DB1/\n        USERS.csv\n        ORDERS.csv\n```\n\nCSV files are UTF-8 with a header row:\n\n```csv\nUSER_ID,USER_NAME,STATUS\n1,Alice,ACTIVE\n2,Bob,INACTIVE\n```\n\nLine endings for input CSV are accepted as either `LF` (`\\n`) or `CRLF` (`\\r\\n`).\n\n### 4. Run\n\n#### Setup (first time only)\n\nScans the DB schema to detect LOB columns and auto-writes `file-patterns` templates into `application.yml`.\n\n```bash\njava -jar flexdblink.jar --setup\n# Target a specific DB only\njava -jar flexdblink.jar --setup --target DB1\n```\n\n\u003e The `file-patterns` generated by `--setup` are **filename format templates for dump output** (e.g., `{ID}.bin`).\n\u003e After generation, open `application.yml` and **edit and maintain them** according to your project's naming conventions.\n\n#### Load\n\n```bash\n# Load initial data (inserts from load/pre/\u003cDB_ID\u003e/)\njava -jar flexdblink.jar --load\n\n# Load with a scenario (inserts load/pre/\u003cDB_ID\u003e/ then load/SCENARIO/\u003cDB_ID\u003e/)\njava -jar flexdblink.jar --load SCENARIO\n\n# Target a specific DB\njava -jar flexdblink.jar --load SCENARIO --target DB1\njava -jar flexdblink.jar --load SCENARIO --target DB1,DB2\n\n# Running without arguments is equivalent to --load (loads pre)\njava -jar flexdblink.jar\n```\n\n\u003e When `confirm-before-load: true` is set, a confirmation prompt (`y/N`) appears before execution.\n\n#### Dump\n\n```bash\n# Dump all DBs under the name SCENARIO (output to dump/SCENARIO/\u003cDB_ID\u003e/)\njava -jar flexdblink.jar --dump SCENARIO\n\n# Dump a specific DB only\njava -jar flexdblink.jar --dump SCENARIO --target DB1\n```\n\n#### Short Options\n\n```bash\njava -jar flexdblink.jar -l SCENARIO -t DB1   # --load SCENARIO --target DB1\njava -jar flexdblink.jar -d SCENARIO -t DB1   # --dump SCENARIO --target DB1\njava -jar flexdblink.jar -s                   # --setup\n```\n\n---\n\n## Building from Source (for developers)\n\n**Requirements**: Java 11+, Maven 3.9+, Docker (for integration tests with Testcontainers)\n\n### Project Structure\n\n```text\nFlexDBLink/                         ← Aggregator POM (flexdblink-parent)\n├── flexdblink/                     ← Core module (CLI + JUnit 5 extension)\n└── flexdblink-maven-plugin/        ← Maven plugin module (load/dump goals)\n```\n\n### Build All Modules\n\n```bash\nmvn clean install -DskipTests\n```\n\nThis builds all modules and installs the following artifacts to the local Maven repository (`~/.m2/repository/io/github/yok/`):\n\n| Module | Artifact | Location |\n| --- | --- | --- |\n| `flexdblink-parent` | POM | `flexdblink-parent/\u003cversion\u003e/` |\n| `flexdblink` | JAR | `flexdblink/\u003cversion\u003e/` |\n| `flexdblink-maven-plugin` | Maven plugin JAR | `flexdblink-maven-plugin/\u003cversion\u003e/` |\n\nThe core module also produces `flexdblink.jar` and `FlexDBLink-distribution.zip` under `flexdblink/target/`.\n\nInstalled and deployed child-module artifacts publish flattened consumer POMs. Downstream builds can\nresolve `flexdblink` and `flexdblink-maven-plugin` without pre-installing or pre-deploying\n`flexdblink-parent`.\n\n### Core Module (`flexdblink`)\n\n```bash\n# Run unit tests + integration tests (requires Docker for Testcontainers)\nmvn clean test -pl flexdblink\n\n# Build distribution archive\nmvn clean package -pl flexdblink -DskipTests\n```\n\n### Maven Plugin Module (`flexdblink-maven-plugin`)\n\n```bash\n# Run all tests: unit (surefire) + integration (failsafe, requires Docker)\n# -am automatically builds the dependent core module first\nmvn clean verify -pl flexdblink-maven-plugin -am\n```\n\n### CI Matrix\n\nThe CI pipeline (`ci.yml`) runs:\n\n| Job | Java Versions | Description |\n| --- | ------------- | ----------- |\n| `test-and-coverage` | 11, 17, 21, 25 | Core module tests with JaCoCo coverage |\n| `maven-plugin-test` | 11 | Plugin unit + integration tests |\n\n---\n\n## CLI Reference\n\n```bash\njava -jar flexdblink.jar [OPTIONS]\n```\n\n| Option | Short | Description |\n| -------- | ------- | ------------- |\n| `--load [scenario]` | `-l` | Load mode. Uses `pre` (or `pre-dir-name` from `application.yml`) when no scenario is specified |\n| `--dump \u003cscenario\u003e` | `-d` | Dump mode. Scenario name is required |\n| `--setup` | `-s` | Setup mode. Scans the DB schema for LOB columns and auto-generates `file-patterns` in `application.yml` |\n| `--target \u003cID,...\u003e` | `-t` | Comma-separated DB IDs to target. When omitted, all connections are processed |\n\n\u003e Overriding Spring properties from the command line is disabled. All configuration must be specified in `application.yml`.\n\n### Example Output\n\n#### **Load execution log (--load COMMON)**\n\n```bash\n$ java -jar flexdblink.jar --load COMMON\n\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::               (v2.7.18)\n\nINFO : Mode: load, Scenario: COMMON, Target DBs: [DB1]\nINFO : [DB1] Table[BINARY_TEST_TABLE]       Initial | inserted=2\nINFO : [DB1] Table[CHAR_CLOB_TEST_TABLE]    Initial | inserted=2\nINFO : [DB1] Table[DATE_TIME_TEST_TABLE]    Initial | inserted=4\nINFO : [DB1] Table[NUMERIC_TEST_TABLE]      Initial | inserted=3\nINFO : [DB1] Table[SAMPLE_BLOB_TABLE]       Initial | inserted=2\nINFO : [DB1] Table[BINARY_TEST_TABLE]       Scenario (INSERT only) | inserted=2\nINFO : [DB1] Table[CHAR_CLOB_TEST_TABLE]    Scenario (INSERT only) | inserted=1\n...\nINFO : == Data loading to all DBs has completed ==\n```\n\n#### **Dump execution log (--dump COMMON)**\n\n```bash\n$ java -jar flexdblink.jar --dump COMMON\n\nINFO : Mode: dump, Scenario: COMMON, Target DBs: [DB1]\nINFO : [DB1] Table[BINARY_TEST_TABLE]    CSV dump completed (UTF-8)\nINFO : [DB1] Table[BINARY_TEST_TABLE]    dumped-records=2, BLOB/CLOB file-outputs=2\nINFO : [DB1] Table[CHAR_CLOB_TEST_TABLE] dumped-records=2, BLOB/CLOB file-outputs=4\n...\nINFO : === All DB dumps completed: Output [dump/COMMON] ===\n```\n\n---\n\n## Directory Structure (under `data-path`)\n\n```bash\n\u003cdata-path\u003e/\n  load/\n    pre/\n      \u003cDB_ID\u003e/\n        TABLE_A.csv\n        TABLE_B.csv\n    \u003cscenario\u003e/\n      \u003cDB_ID\u003e/\n        TABLE_A.csv           # Incremental data (scenario-specific additions)\n  files/\n    Foo_001.bin               # LOB content (referenced from CSV via file:xxx)\n  dump/\n    \u003cscenario\u003e/\n      \u003cDB_ID\u003e/\n        *.csv                 # Dump output\n        files/                # Dumped LOB files\n```\n\n---\n\n## Working with LOB (BLOB/CLOB)\n\n**On load**: Write `file:filename` in a CSV cell to read and insert `\u003cdata-path\u003e/files/filename`.\n\n```csv\nID,FILE_DATA\n001,file:LeapSecond_001.dat\n002,file:LeapSecond_002.dat\n```\n\n**On dump**: LOB columns are written as files under `files/`, and the CSV cell is populated with `file:xxx`.\nThe filename template is controlled by `file-patterns`.\n\n---\n\n## application.yml Configuration Reference\n\n```yaml\n# Base path for CSV and LOB files (required)\ndata-path: /absolute/path/to/data\n\ndbunit:\n  pre-dir-name: pre             # Initial load directory name (default: pre)\n  csv:\n    format:\n      date: \"yyyy-MM-dd\"                    # Dump output format / preferred parse format on load\n      time: \"HH:mm:ss\"                      # Same as above\n      dateTime: \"yyyy-MM-dd HH:mm:ss\"       # Same as above\n      dateTimeWithMillis: \"yyyy-MM-dd HH:mm:ss.SSS\"  # Same as above\n  config:\n    allow-empty-fields: true    # Allow empty fields\n    batched-statements: true    # Use batch execution\n    batch-size: 100             # Batch size\n\n# DB connection settings (multiple entries supported)\nconnections:\n  - id: DB1\n    url: jdbc:oracle:thin:@localhost:1521/OPEDB\n    user: oracle\n    password: password\n    driver-class: oracle.jdbc.OracleDriver\n  - id: DB2\n    url: jdbc:postgresql://localhost:5432/mydb\n    user: postgres\n    password: password\n    driver-class: org.postgresql.Driver\n\n# LOB filename templates for dump output\n# Column name placeholders like {COL_NAME} are replaced with the row's values\nfile-patterns:\n  SAMPLE_BLOB_TABLE:\n    FILE_DATA: \"LeapSecond_{ID}.dat\"\n  CHAR_CLOB_TEST_TABLE:\n    CLOB_COL: \"char_clob_{ID}.clob\"\n    NCLOB_COL: \"char_clob_{ID}.nclob\"\n\n# Tables to exclude from dump\ndump:\n  exclude-tables:\n    - flyway_schema_history\n```\n\n| Key | Required | Description |\n| ----- | ---------- | ------------- |\n| `data-path` | ✅ | Base path for CSV and LOB files |\n| `dbunit.pre-dir-name` | | Initial load directory name (default: `pre`) |\n| `dbunit.confirm-before-load` | | When `true`, shows a confirmation prompt before `--load` executes (default: `false`) |\n| `dbunit.csv.format.date` | | **Dump output format** and **preferred parse format on load** for DATE (default: `yyyy-MM-dd`) |\n| `dbunit.csv.format.time` | | **Dump output format** and **preferred parse format on load** for TIME (default: `HH:mm:ss`) |\n| `dbunit.csv.format.dateTime` | | **Dump output format** and **preferred parse format on load** for TIMESTAMP (default: `yyyy-MM-dd HH:mm:ss`) |\n| `dbunit.csv.format.dateTimeWithMillis` | | **Dump output format** and **preferred parse format on load** for TIMESTAMP with milliseconds (default: `yyyy-MM-dd HH:mm:ss.SSS`) |\n| `connections[].id` | ✅ | DB identifier, matched against the `--target` option |\n| `connections[].url` | ✅ | JDBC URL. Fallback dialect detection source when `driver-class` is omitted |\n| `connections[].user` | ✅ | Database user name |\n| `connections[].password` | | Database password |\n| `connections[].driver-class` | | Preferred dialect detection source for each connection entry |\n| `file-patterns` | | LOB filename templates for dump. Generate a template with `--setup`, then edit and maintain manually |\n| `dump.exclude-tables` | | Tables to exclude from dump |\n\n---\n\n## Published Maven Artifacts\n\nThis repository publishes Maven artifacts via GitHub Packages for `y-ok/FlexDBLink`.\nConfigure GitHub Packages access for this repository in your build environment before resolving these artifacts.\nPackage overview: [GitHub Packages](https://github.com/y-ok?tab=packages\u0026repo_name=FlexDBLink)\n\n| Artifact | Purpose | Notes |\n| ----- | ----- | ----- |\n| `io.github.yok:flexdblink` | Core library artifact with the JUnit 5 extension (`@LoadData`) | Use this dependency when consuming FlexDBLink from tests or Spring-based test suites |\n| `io.github.yok:flexdblink-maven-plugin` | Maven plugin artifact for `load` / `dump` | Use this artifact inside Maven plugin configuration |\n\n---\n\n## Maven Plugin (`flexdblink-maven-plugin`)\n\n`flexdblink-maven-plugin` is a published GitHub Packages artifact for this repository. Use the plugin\ncoordinates shown in the `POM Plugin Example` section below, and make sure GitHub Packages access is\nconfigured in your build environment before resolving the plugin.\nThe plugin excludes `flyway_schema_history` by default so common Flyway-managed schemas work\nwithout extra configuration.\n\nFlexDBLink can also be used as a Maven plugin wrapper for `load` and `dump`, while reusing the\nexisting core logic (`DataLoader` / `DataDumper`).\n\n### Configuration Split\n\n- Store DB connection settings in `~/.m2/settings.xml` (`servers/server`)\n- Store `dataPath`, `filePatterns`, and `dbunit` settings in your POM plugin configuration\n\n### POM Repository Example\n\nAdd GitHub Packages as both a dependency repository and a plugin repository before using the\npublished artifacts.\n\n```xml\n\u003crepositories\u003e\n  \u003crepository\u003e\n    \u003cid\u003egithub\u003c/id\u003e\n    \u003cname\u003eGitHub Packages - FlexDBLink\u003c/name\u003e\n    \u003curl\u003ehttps://maven.pkg.github.com/y-ok/FlexDBLink\u003c/url\u003e\n  \u003c/repository\u003e\n\u003c/repositories\u003e\n\n\u003cpluginRepositories\u003e\n  \u003cpluginRepository\u003e\n    \u003cid\u003egithub\u003c/id\u003e\n    \u003cname\u003eGitHub Packages - FlexDBLink\u003c/name\u003e\n    \u003curl\u003ehttps://maven.pkg.github.com/y-ok/FlexDBLink\u003c/url\u003e\n  \u003c/pluginRepository\u003e\n\u003c/pluginRepositories\u003e\n```\n\n### `settings.xml` Example\n\n```xml\n\u003csettings\u003e\n  \u003cservers\u003e\n    \u003cserver\u003e\n      \u003cid\u003eflexdblink-db1\u003c/id\u003e\n      \u003cusername\u003eapp_user\u003c/username\u003e\n      \u003cpassword\u003epassword\u003c/password\u003e\n      \u003cconfiguration\u003e\n        \u003cdbId\u003eDB1\u003c/dbId\u003e\n        \u003curl\u003ejdbc:postgresql://localhost:5432/app\u003c/url\u003e\n        \u003cdriverClass\u003eorg.postgresql.Driver\u003c/driverClass\u003e\n      \u003c/configuration\u003e\n    \u003c/server\u003e\n  \u003c/servers\u003e\n\u003c/settings\u003e\n```\n\n### POM Plugin Example\n\n```xml\n\u003cplugin\u003e\n  \u003cgroupId\u003eio.github.yok\u003c/groupId\u003e\n  \u003cartifactId\u003eflexdblink-maven-plugin\u003c/artifactId\u003e\n  \u003cversion\u003e${flexdblink.version}\u003c/version\u003e\n  \u003cconfiguration\u003e\n    \u003cserverIds\u003e\n      \u003cserverId\u003eflexdblink-db1\u003c/serverId\u003e\n    \u003c/serverIds\u003e\n\n    \u003cdataPath\u003e${project.basedir}/src/test/resources/dbunit\u003c/dataPath\u003e\n\n    \u003cdbunit\u003e\n      \u003cpreDirName\u003epre\u003c/preDirName\u003e\n      \u003ccsv\u003e\n        \u003cformat\u003e\n          \u003cdate\u003eyyyy-MM-dd\u003c/date\u003e\n          \u003ctime\u003eHH:mm:ss\u003c/time\u003e\n          \u003cdateTime\u003eyyyy-MM-dd HH:mm:ss\u003c/dateTime\u003e\n          \u003cdateTimeWithMillis\u003eyyyy-MM-dd HH:mm:ss.SSS\u003c/dateTimeWithMillis\u003e\n        \u003c/format\u003e\n      \u003c/csv\u003e\n      \u003cconfig\u003e\n        \u003callowEmptyFields\u003etrue\u003c/allowEmptyFields\u003e\n        \u003cbatchedStatements\u003etrue\u003c/batchedStatements\u003e\n        \u003cbatchSize\u003e100\u003c/batchSize\u003e\n      \u003c/config\u003e\n    \u003c/dbunit\u003e\n\n    \u003cfilePatterns\u003e\n      \u003cpattern\u003e\n        \u003ctableName\u003eemployee\u003c/tableName\u003e\n        \u003ccolumnName\u003ephoto\u003c/columnName\u003e\n        \u003cfilename\u003e{ID}_photo.bin\u003c/filename\u003e\n      \u003c/pattern\u003e\n    \u003c/filePatterns\u003e\n\n    \u003cexcludeTables\u003e\n      \u003cexcludeTable\u003ebatch_job_instance\u003c/excludeTable\u003e\n    \u003c/excludeTables\u003e\n  \u003c/configuration\u003e\n\u003c/plugin\u003e\n```\n\n### Plugin JDBC Driver Dependencies\n\nAdd only the JDBC drivers you actually use inside the plugin declaration.\n\n```xml\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.postgresql\u003c/groupId\u003e\n    \u003cartifactId\u003epostgresql\u003c/artifactId\u003e\n    \u003cversion\u003e42.7.10\u003c/version\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\nUse the matching coordinates for your database:\n\n- Oracle: `com.oracle.database.jdbc:ojdbc8` (or `ojdbc10`)\n- PostgreSQL: `org.postgresql:postgresql`\n- MySQL: `com.mysql:mysql-connector-j`\n- SQL Server: `com.microsoft.sqlserver:mssql-jdbc`\n\n`flyway_schema_history` is excluded by default. Use `excludeTables` to add project-specific tables\non top of that default list.\n\n### Commands\n\n- `mvn flexdblink:load` → loads `pre` only\n- `mvn flexdblink:load -Dflexdblink.scenario=scenario1` → loads `pre` and `scenario1`\n- `mvn flexdblink:dump` → dumps to `${dataPath}/dump/\u003cyyyyMMddHHmmss\u003e`\n- `mvn flexdblink:dump -Dflexdblink.scenario=scenario1` → dumps to `${dataPath}/dump/scenario1`\n\n### Debug Logging\n\nEnable `DEBUG` only for FlexDBLink logs during Maven plugin execution:\n\n```bash\nmvn -Dorg.slf4j.simpleLogger.log.io.github.yok.flexdblink=debug flexdblink:load\n```\n\n### VS Code Classpath Note\n\nIf you see `is not on the classpath of project flexdblink, only syntax errors are reported`,\nopen the repository with the included workspace file `FlexDBLink.code-workspace`.\nThe workspace intentionally registers only the repository root and relies on Maven import for\nsubprojects (including `flexdblink-maven-plugin`) to avoid duplicate project registration.\n\nIf the warning still appears after opening the workspace, run `Java: Clean Java Language Server Workspace`\nfrom the VS Code command palette and reopen the workspace.\nIf needed, also run `Maven: Reload Projects`.\n\n---\n\n## JUnit 5 Extension (`@LoadData`)\n\n### Maven Dependency\n\n`io.github.yok:flexdblink` is the published artifact that provides the JUnit 5 extension. Resolve\nthis dependency from GitHub Packages for this repository after configuring GitHub Packages access in\nyour build environment. The `repositories` example above is also required when resolving this\ndependency from your test project.\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eio.github.yok\u003c/groupId\u003e\n  \u003cartifactId\u003eflexdblink\u003c/artifactId\u003e\n  \u003cversion\u003e${flexdblink.version}\u003c/version\u003e\n  \u003cscope\u003etest\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\nAlso add the JDBC driver for your target database as a normal project dependency (typically with\n`test` scope). Use the same coordinates listed in the Maven plugin section, but declare them in\nyour project's `\u003cdependencies\u003e` instead of `\u003cplugin\u003e\u003cdependencies\u003e`.\n\nSimply annotate your test with `@LoadData` to automatically inject the dataset before the test and roll it back on completion.\nThis integrates with Spring Test transaction management (`@Transactional`), ensuring the DB state is reliably restored after each test method.\n\nA **Spring Test execution context** is required (`@SpringBootTest`, `@MybatisTest`, `@ExtendWith(SpringExtension.class)`, etc.).\n\nFor each test execution, FlexDBLink applies exactly one effective `@LoadData` annotation:\n\n- If the test method has `@LoadData`, the method-level annotation is used\n- Otherwise, the class-level annotation is used\n\nThe method-level annotation does not merge with the class-level annotation. It fully overrides the\nclass-level `scenario` and `dbNames` for that test method.\n\n### Usage\n\n```java\n@MybatisTest\n@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)\n@Import(MyDataSourceConfig.class)\n@LoadData(scenario = \"NORMAL\", dbNames = \"BBB\")   // ← applied to the entire class\nclass UserMapperTest {\n\n    @Autowired\n    private UserMapper mapper;\n\n    @Test\n    @LoadData(scenario = \"ADMIN\", dbNames = \"BBB\") // ← applied to a single method (overrides class-level)\n    void findById_returnsExpectedRecord() {\n        User user = mapper.findById(1L);\n        assertNotNull(user);\n        assertEquals(\"Alice\", user.getName());\n    }\n}\n```\n\nThis means the following method loads only `ADMIN` for `BBB`. It does not load both `NORMAL` and\n`ADMIN`.\n\n### Test Resource Layout Convention\n\n```bash\n# Per-db tests (single or multiple dbNames)\nsrc/test/resources/\u003cpackage\u003e/\u003cTestClassName\u003e/\u003cscenario\u003e/input/\u003cdbName\u003e/*.csv\nsrc/test/resources/\u003cpackage\u003e/\u003cTestClassName\u003e/\u003cscenario\u003e/input/\u003cdbName\u003e/files/*  # LOB content\n```\n\n\u003e **Paths outside this convention will cause an error.**\n\nWhen method-level `@LoadData` is used, the method-level `scenario` directory is the one that is\nresolved for that test method.\n\n### `@LoadData` Parameters\n\n| Parameter | Description |\n| ----------- | ------------- |\n| `scenario` | Required. Scenario directory names. Single value shorthand is allowed. E.g., `\"NORMAL\"` |\n| `dbNames` | Required. Target DB directory names. Single value shorthand is allowed. E.g., `\"AAA\"`, `{\"AAA\",\"BBB\"}` |\n\nBoth parameters are validated before loading starts. Blank `scenario` values and unmapped `dbNames`\nfail fast with an exception.\n\n### Using `FlexAssert` with `@LoadData`\n\nWhen `FlexAssert` is used in the same test, it resolves the expected dataset from the same effective\n`@LoadData` annotation that was applied for loading.\n\nExpected resource layout:\n\n```bash\nsrc/test/resources/\u003cpackage\u003e/\u003cTestClassName\u003e/\u003cscenario\u003e/expected/\u003cdbName\u003e/*.csv\nsrc/test/resources/\u003cpackage\u003e/\u003cTestClassName\u003e/\u003cscenario\u003e/expected/\u003cdbName\u003e/files/*  # LOB content\n```\n\nIf a method-level `@LoadData` overrides the class-level annotation, `FlexAssert` also uses that\nmethod-level `scenario` when resolving `expected/\u003cdbName\u003e`.\n\n### DataSource Mapping (`flexdblink.properties`)\n\n`@LoadData` resolves the target database by **DataSource bean name**.\n\nConfig file path:\n\n```properties\nsrc/test/resources/flexdblink.properties\n```\n\nConfig format:\n\n```properties\nflexdblink.load.datasource.aaa=aaaRoutingDataSource\nflexdblink.load.datasource.bbb=bbbRoutingDataSource\n```\n\n- Key format: `flexdblink.load.datasource.\u003cdbId\u003e`\n- `\u003cdbId\u003e` is matched case-insensitively (`input/BBB` matches key `bbb`)\n- TransactionManager bean-name mapping is not required\n\n#### When Is Mapping Required?\n\n| Test mode | Is `flexdblink.properties` required? | Resolution behavior |\n| -------- | -------- | -------- |\n| Any `@LoadData` usage (`dbNames` specified) | Yes | Every dbId in `dbNames` must be mapped to a DataSource bean |\n\n#### Recommended Examples\n\nSingle DB:\n\n```java\n@LoadData(scenario = \"NORMAL\", dbNames = \"AAA\")\n```\n\nMulti DB:\n\n```java\n@LoadData(scenario = \"NORMAL\", dbNames = {\"AAA\", \"BBB\"})\n```\n\n```properties\nflexdblink.load.datasource.aaa=aaaRoutingDataSource\nflexdblink.load.datasource.bbb=bbbRoutingDataSource\n```\n\n#### Typical Errors\n\n- `DataSource mapping was not found for dbId=...`\n  - Add `flexdblink.load.datasource.\u003cdbId\u003e=\u003cbeanName\u003e` to `flexdblink.properties`\n- `Configured DataSource bean was not found...`\n  - Verify the mapped bean name exists in the Spring test context\n- `@LoadData dbNames must be specified...`\n  - Add `dbNames = {...}` to every `@LoadData`\n\n---\n\n## Supported Databases and Type Coverage\n\n### Oracle\n\n| SQL Type | Format / Notes |\n| ---------- | ---------------- |\n| `DATE` | `yyyy-MM-dd` |\n| `TIMESTAMP(6)` | `yyyy-MM-dd HH:mm:ss.SSS` |\n| `TIMESTAMP WITH TIME ZONE` / `WITH LOCAL TIME ZONE` | `yyyy-MM-dd HH:mm:ss +HHMM` |\n| `INTERVAL YEAR TO MONTH` | `Y-M` |\n| `INTERVAL DAY TO SECOND` | `D H:M:S` |\n| `CLOB` / `NCLOB` / `BLOB` | External file reference via `file:xxx` |\n| `NUMBER`, `VARCHAR2`, `CHAR`, `NVARCHAR2`, `NCHAR`, `RAW`, `BINARY_FLOAT`, `BINARY_DOUBLE` | Standard support |\n\n### PostgreSQL\n\n| SQL Type | Format / Notes |\n| ---------- | ---------------- |\n| `DATE` | `yyyy-MM-dd` |\n| `TIME` | `HH:mm:ss` |\n| `TIMESTAMP` | `yyyy-MM-dd HH:mm:ss[.fraction]` |\n| `TIMESTAMPTZ` | `yyyy-MM-dd HH:mm:ss[.fraction]+HHMM` |\n| `BYTEA` | External file reference via `file:xxx` |\n| `BIGINT`, `NUMERIC`, `REAL`, `DOUBLE PRECISION`, `VARCHAR`, `CHAR`, `TEXT`, `XML` | Standard support |\n\n### MySQL\n\n| SQL Type | Format / Notes |\n| ---------- | ---------------- |\n| `DATE` | `yyyy-MM-dd` |\n| `TIME` | `HH:mm:ss` |\n| `DATETIME` / `TIMESTAMP` | `yyyy-MM-dd HH:mm:ss[.fraction]` |\n| `YEAR` | `yyyy` |\n| `TINYBLOB` / `BLOB` / `MEDIUMBLOB` / `LONGBLOB` | External file reference via `file:xxx` |\n| Integer types, `DECIMAL`, `FLOAT`, `DOUBLE`, `BIT`, `BOOLEAN`, `CHAR`, `VARCHAR`, `TEXT` family, `ENUM`, `SET`, `JSON`, `BINARY`, `VARBINARY` | Standard support |\n\n### SQL Server\n\n| SQL Type | Format / Notes |\n| ---------- | ---------------- |\n| `DATE` | `yyyy-MM-dd` |\n| `TIME` | `HH:mm:ss` |\n| `DATETIME2` | `yyyy-MM-dd HH:mm:ss[.fraction]` |\n| `VARBINARY` | External file reference via `file:xxx` |\n| `BIGINT`, `INT`, `SMALLINT`, `TINYINT`, `DECIMAL`, `NUMERIC`, `FLOAT`, `REAL`, `BIT`, `CHAR`, `VARCHAR`, `NCHAR`, `NVARCHAR`, `XML` | Standard support |\n\n---\n\n## Accepted Date/Time Formats on CSV Load\n\nOn `--load`, the format specified by `dbunit.csv.format.*` is tried first.\nIf no match is found, the following formats are attempted in order (applies to all databases).\n\n### Date (DATE)\n\n| Format | Example |\n| -------- | --------- |\n| `yyyy-MM-dd` (ISO) | `2026-02-25` |\n| `yyyy/MM/dd` | `2026/02/25` |\n| `yyyyMMdd` (basic ISO) | `20260225` |\n| `yyyy.MM.dd` | `2026.02.25` |\n| `yyyy年M月d日` (Japanese) | `2026年2月25日` |\n\n### Time (TIME)\n\n| Format | Example |\n| -------- | --------- |\n| `HH:mm:ss[.fraction]` (seconds and fractional seconds are optional) | `14:30:00.123456789` |\n| `HH:mm` | `14:30` |\n| `HHmmss[.fraction]` (no delimiter) | `143000.123` |\n| `HHmm` | `1430` |\n\n### Timestamp (TIMESTAMP)\n\nAll combinations of date and time formats are tried, with `dbunit.csv.format.dateTime` / `dateTimeWithMillis` applied first.\n\n\u003e DB-specific extended types (e.g., Oracle `TIMESTAMP WITH TIME ZONE`, SQL Server `DATETIMEOFFSET`) have additional formats in each DB's implementation. See the type coverage tables for details.\n\n---\n\n## CSV Line Ending Behavior (Load / Dump)\n\n| Operation | Behavior |\n| --------- | -------- |\n| `--load` | Input CSV line endings `LF` and `CRLF` are supported. |\n| `--dump` | Output CSV uses `System.lineSeparator()` of the JVM process environment. |\n\n`--dump` output therefore depends on where the process runs:\n\n- Windows runtime: `CRLF` (`\\r\\n`)\n- Linux/macOS runtime: `LF` (`\\n`)\n\nIf you run FlexDBLink in a Linux container (including on a Windows host), dumped CSV line endings are `LF` because the process environment is Linux.\n\n---\n\n## Best Practices\n\n**No need to maintain `table-ordering.txt` manually**\nFlexDBLink resolves FK dependencies at runtime and loads parent tables before child tables automatically. `table-ordering.txt` is not required as an input file for load operations.\n\n**Configure tables to exclude**\nAdd tables like `flyway_schema_history` to `dump.exclude-tables` so they are not loaded or dumped.\n\n**Standardize date/time formats across your team**\nExplicitly configuring `dbunit.csv.format.*` aligns the dump output format with the preferred load parse format, preventing inconsistencies due to environment differences.\nEven without configuration, multiple formats such as `yyyy-MM-dd` / `yyyy/MM/dd` are tried automatically, so existing CSV files can be loaded as-is.\n\n**Grow `file-patterns` yourself**\n`--setup` only generates a template for filename formats. Edit and maintain `file-patterns` in `application.yml` manually to match your project's naming conventions.\n\n**Centralize LOBs in `files/`**\nStore BLOB/CLOB binaries in the `files/` directory rather than in CSV, and consider applying Git LFS to that directory.\n\n**Choose a data format that produces readable diffs**\nCSV is the simplest, but JSON/YAML is better for nested structures. Choose based on your team's needs.\n\n---\n\n## Docker Sample Environment (Oracle 19c)\n\nA sample using an Oracle 19c Docker environment is available in the `script/` directory.\n\n- [Oracle 19c (Docker) Setup and FlexDBLink Sample Run](script/README_jp.md)\n\n---\n\n## Internal Implementation\n\n- **DBUnit** is used internally for dataset management, but its API is fully abstracted by FlexDBLink.\n- Separate implementations handle the type characteristics of Oracle, PostgreSQL, MySQL, and SQL Server.\n\n---\n\n## License\n\nThis repository is provided under the **Apache License 2.0**. See [LICENSE](LICENSE.txt) for details.\n\n---\n\n## Contributing\n\nBug reports and feature requests are welcome. Issues and PRs are appreciated.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fy-ok%2Fflexdblink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fy-ok%2Fflexdblink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fy-ok%2Fflexdblink/lists"}