Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ public
resources
dist
hugo_stats.json

.idea/
72 changes: 72 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Contributing to SQL Components

Thank you for helping improve this project. This document explains how to work with the repository in a way that keeps changes reviewable and CI-friendly.

## Code of conduct

Be respectful and assume good intent in issues and pull requests. Follow the tone set in existing discussions and GitHub’s community guidelines.

## Before you start

1. **Read the docs** — [docs/README.md](docs/README.md) and the module pages under [docs/](docs/) explain architecture, Maven layout, and the datastore workflow.
2. **Check the license** — [LICENSE](LICENSE) (Apache 2.0). Contributions are expected to be licensed under the same terms unless explicitly stated otherwise.

## Development setup

- **JDK**: The build uses **Java 17** in the Maven POMs. A JDK that matches `maven.compiler.source` / `target` is required.
- **Maven**: Use the Maven Wrapper if present, or a recent Maven 3.x aligned with the project.
- **Database (optional)**: For integration-style tests, PostgreSQL can be started with root `docker-compose.yml` (port **5432**, database `moviedb`). Align [database.properties](database.properties) with your environment.

## Building and testing

From the repository root (builds **core** and **compiler** only):

```bash
mvn clean verify
```

To skip tests when you only need a compile:

```bash
mvn clean package -Dmaven.test.skip=true
```

To build and test the **datastore** example module (not part of the default reactor):

```bash
mvn -f datastore/pom.xml clean test
```

Generate sources into `datastore/src/main/java` before datastore tests if that directory is empty (for example by running the compiler module’s generation tests or your own small driver that calls `Application.compile(new org.sqlcomponents.compiler.java.JavaCompiler())`).

## Style and quality

- **Checkstyle** runs in the `validate` phase. Fix violations rather than disabling rules unless there is a strong reason and a suppression entry is agreed with maintainers.
- Match **existing code style**: naming, formatting, and Javadoc level in the files you touch.
- Prefer **small, focused PRs** with a clear description of behavior change.

## How to contribute changes

1. **Fork** the repository (if contributing from outside the main org) and create a **feature branch** from the appropriate default branch.
2. **Implement** your change with tests where behavior is non-trivial or regression-prone.
3. **Run** `mvn clean verify` (and datastore tests if you changed generation or example code paths).
4. **Open a pull request** that:
- Summarizes the problem and the solution in complete sentences.
- Links related issues (e.g. `Fixes #123`).
- Calls out any breaking changes, migration steps, or follow-up work.

## Issues

Use the GitHub issue templates under `.github/ISSUE_TEMPLATE/` when filing bugs, features, or CI reports. Include:

- Expected vs actual behavior
- JDK and Maven versions
- Relevant logs or minimal reproduction steps

## Security

Do not open public issues for **undisclosed security vulnerabilities**. Contact maintainers through a private channel if one is documented on the repository; otherwise use GitHub’s security advisory feature if enabled.

## Questions

If something in [docs/](docs/) is unclear or wrong, opening an issue or a documentation-only PR is welcome.
69 changes: 69 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# SQL Components documentation

This folder describes the **sqlcomponents** multi-module Maven project: how it reads database metadata, maps it to a Java-friendly model, generates persistence-oriented Java sources, and how the **datastore** example module validates that story end-to-end.

The root [README.md](../README.md) (sqlbridge notes, Docker, Maven commands) stays the quick operational entry; use this `docs/` tree for **architecture and module behavior**.

---

## High-level picture

SQL Components is a **code generator** built around JDBC:

1. **Connect** to a live database using URL, credentials, and driver settings held in `Application`.
2. **Crawl** catalog metadata (tables, columns, keys, indexes, procedures, types, …) into relational POJOs in the **core** module.
3. **Map** columns and entities to Java types and ORM structures (today: **`JavaMapper`** in the **compiler** module).
4. **Generate** Java source files with **FreeMarker** templates—notably a façade **`DataManager`**, table-aligned **`…Store`** classes, and **`Record`** / enum-style types.
5. **Consume** the generated code from application or test code (the **datastore** module demonstrates this against PostgreSQL).

```mermaid
flowchart LR
subgraph ingest [Ingestion]
JDBC[JDBC metadata]
Crawler[Crawler in core]
end
subgraph model [Model]
App[Application ORM Entity]
end
subgraph gen [Generation]
JC[JavaCompiler]
FTL[FreeMarker templates]
end
subgraph use [Usage]
Stores[DataManager and Stores]
end
JDBC --> Crawler
Crawler --> App
App --> JC
FTL --> JC
JC --> Stores
```

**Design intent** (aligned with the root README themes): catch schema issues early, support multiple dialects, and emit readable Java that wraps SQL construction and execution—without replacing the database at runtime.

---

## Core-level reading guide

Read in this order if you are onboarding to the codebase:

| Order | Document | What you learn |
|-------|----------|----------------|
| 1 | [Project structure](project-structure.md) | Directories, which Maven modules build from the root reactor, dependency direction, where templates and generated files live. |
| 2 | [Core module](core.md) | `Crawler`, relational model types, `Application`, `Compiler` SPI, YAML loading via `CoreConsts`. |
| 3 | [Compiler module](compiler.md) | `JavaCompiler` pipeline, `JavaMapper`, FreeMarker template layout, how tests configure output paths. |
| 4 | [Datastore module](datastore.md) | Example/integration tests, dependency on generated `org.example` code, building with `mvn -f datastore/pom.xml`. |

---

## Contributing and license

- **[CONTRIBUTING.md](../CONTRIBUTING.md)** — How to propose changes, run checks, and interact with maintainers.
- **[LICENSE](../LICENSE)** — Legal terms for using and redistributing the project.

---

## Related links

- Upstream context in POM: [https://github.com/sqlcomponents/sqlcomponents](https://github.com/sqlcomponents/sqlcomponents)
- Root [README.md](../README.md) — Docker Compose, `mvn` recipes, JDK notes.
94 changes: 94 additions & 0 deletions docs/compiler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Compiler module

The **compiler** module (`org.sqlcomponents:compiler`) turns a populated `Application` (from **core**) into Java source files: a **DataManager**, per-entity **Store** classes, **Record** (or similar) model types, and **enum**-style artifacts for certain database types. It implements `org.sqlcomponents.core.compiler.Compiler` via [`JavaCompiler`](../compiler/src/main/java/org/sqlcomponents/compiler/java/JavaCompiler.java).

For how metadata reaches `Application`, see [Core module](core.md). For where output is written in this repo’s workflow, see [Datastore module](datastore.md).

## End-to-end pipeline (`JavaCompiler.compile`)

At a high level, `JavaCompiler`:

1. **Optional Flyway migrations** — If Flyway is on the classpath and `src/main/resources/db/migration` exists relative to the process working directory, runs Flyway against a datasource built from `Application`, then closes the datasource. This is best-effort and environment-specific; see source for details.
2. **Map relational model to ORM view** — Constructs [`JavaMapper`](../compiler/src/main/java/org/sqlcomponents/compiler/mapper/JavaMapper.java), which extends core’s [`Mapper`](../core/src/main/java/org/sqlcomponents/core/mapper/Mapper.java), and assigns the resulting `ORM` on `Application`.
3. **Emit Java** — Uses FreeMarker via [`FTLTemplate`](../compiler/src/main/java/org/sqlcomponents/compiler/template/FTLTemplate.java) to render:
- **Manager** — [`Manager.ftl`](../compiler/src/main/resources/template/java/Manager.ftl) → `DataManager.java` under the root package folder.
- **Store** — [`Store.ftl`](../compiler/src/main/resources/template/java/Store.ftl) → `{Entity}Store.java` under each entity’s DAO package.
- **Model / record** — [`Record.ftl`](../compiler/src/main/resources/template/java/Record.ftl) → `{Entity}.java` under the bean package.
- **Enum / type** — For entities whose type is an enumerated DB type, [`Enum.ftl`](../compiler/src/main/resources/template/java/Enum.ftl) → `{Entity}Type.java`.

Entity processing uses a **parallel stream** over `orm.getEntities()` for throughput.

`Application.compile(Compiler)` (in core) **deletes the entire `srcFolder` tree** before calling `Compiler.compile`, so every run is a clean generation.

## `JavaMapper`

[`JavaMapper`](../compiler/src/main/java/org/sqlcomponents/compiler/mapper/JavaMapper.java) is responsible for mapping SQL column semantics (via core’s `Column` / `ColumnType`) to Java types—for example primitives, `String`, `UUID`, `BigDecimal`, JTS geometry types, JSON node types, and time API classes. The mapper feeds the templates so generated fields and method signatures match the database.

## FreeMarker templates

Templates live under [`compiler/src/main/resources/template/java/`](../compiler/src/main/resources/template/java/). `FTLTemplate` loads them from the classpath relative to `JavaCompiler`.

Notable groups:

| Subdirectory / file | Purpose |
|---------------------|-----------|
| `Manager.ftl`, `Store.ftl`, `Record.ftl`, `Enum.ftl` | Top-level artifacts per entity or application. |
| `column/*.ftl` | Fragments for SQL/expression handling per Java column kind (e.g. `BooleanColumn.ftl`, `UUIDColumn.ftl`, geometry columns). |
| `method/*.ftl` | Statement builders: `SelectStatement`, `InsertStatement`, `UpdateStatement`, `DeleteStatement`, `MViewRefresh`. |
| `query/*.ftl`, `clause/*.ftl` | Query and WHERE composition. |
| `base.ftl`, `jdbcbase.ftl`, `SqlBuilder.ftl`, … | Shared includes. |
| `template/directive/` | Custom FreeMarker directives (e.g. column selection). |

Generated `package-info.java` files are also written with a minimal `package …;` declaration for each output package.

## Dependencies (`compiler/pom.xml`)

- **FreeMarker** — Template engine.
- **JTS Core** — Geometry types referenced by `JavaMapper` / templates for spatial columns.
- **Flyway** (`provided` / optional usage) — Migration hook described above.
- **core** — Same-version `org.sqlcomponents:core`.

Drivers and pooling come from the **parent** POM when running in tests or integrated apps.

## How to run code generation in practice

### Properties-based setup (tests / local dev)

[`CompilerTestUtil.getApplication()`](../compiler/src/test/java/org/sqlcomponents/compiler/java/util/CompilerTestUtil.java) builds an `Application` when `SQLCOMPONENTS_CONFIG` is **not** set:

- Reads [`database.properties`](../database.properties) from the current working directory or parent (`../database.properties`).
- Uses `DATABASE_TYPE` env var or defaults to `postgres` for property key prefix (`postgres.datasource.url`, …).
- Sets `rootPackage`, encryption lists, insert/update maps, and **`srcFolder`** to `datastore/src/main/java` (or `../datastore/src/main/java` depending on cwd).

Then:

```java
Application application = CompilerTestUtil.getApplication();
application.compile(new JavaCompiler());
```

Run from Maven with the working directory that matches your paths (often `compiler/` for tests).

### YAML-based setup (CI / explicit config)

When **`SQLCOMPONENTS_CONFIG`** points to a YAML file:

- `Application` is built with [`CoreConsts.buildApplication(File)`](../core/src/main/java/org/sqlcomponents/core/utils/CoreConsts.java).
- **`SOURCE_FOLDER`** must be set to the output directory for generated sources (throws if missing).

## SPI: `Compiler` interface

The compiler module is the reference implementation of:

```java
void compile(Application application) throws SQLException;
```

Other implementations could target different languages or layouts as long as they accept `Application`.

## Related documentation

- [Core module](core.md)
- [Datastore module](datastore.md)
- [Project structure](project-structure.md)
- [Documentation index](README.md)
78 changes: 78 additions & 0 deletions docs/core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Core module

The **core** module (`org.sqlcomponents:core`) is the foundation of SQL Components. It connects to a database through JDBC, reads catalog metadata, and represents that metadata as Java objects. It also defines the configuration surface (`Application`) and the small **Compiler** SPI that the **compiler** module implements.

For repository layout and Maven coordinates, see [Project structure](project-structure.md).

## Responsibilities at a glance

1. **Introspection**: Walk JDBC `DatabaseMetaData` (and related queries) to build a graph of schemas, tables, columns, keys, indexes, procedures, and user-defined types.
2. **Domain model**: Express that graph as immutable-friendly POJOs under `org.sqlcomponents.core.model` and `org.sqlcomponents.core.model.relational`.
3. **Configuration**: Hold everything needed to open a datasource, filter objects, name Java packages, and tune ORM behavior—primarily via `Application` and nested `ORM`.
4. **Compilation contract**: Declare `org.sqlcomponents.core.compiler.Compiler` so other modules can generate artifacts without core knowing about FreeMarker or Java source layout.

## Package map

| Package | Role |
|---------|------|
| `org.sqlcomponents.core.crawler` | `Crawler` base logic; database-specific subclasses (e.g. PostgreSQL, MySQL) refine behavior. |
| `org.sqlcomponents.core.crawler.util` | Helpers such as `DataSourceUtil` for constructing datasources. |
| `org.sqlcomponents.core.model` | Top-level app concepts: `Application`, `Entity`, `ORM`, `Method`, `Service`, … |
| `org.sqlcomponents.core.model.relational` | Relational catalog types: `Database`, `Table`, `Column`, `Key`, `Index`, `Procedure`, `Type`, constraints, `Package`, enums (`ColumnType`, `DBType`, `TableType`, …). |
| `org.sqlcomponents.core.compiler` | `Compiler` interface: `void compile(Application application) throws SQLException`. |
| `org.sqlcomponents.core.mapper` | Abstract `Mapper` used by language-specific mappers (e.g. `JavaMapper` in the compiler module). |
| `org.sqlcomponents.core.exception` | Shared error types. |
| `org.sqlcomponents.core.utils` | `CoreConsts` and other utilities. |

## Crawler vs dialect crawlers

- **`Crawler`** ([`Crawler.java`](../core/src/main/java/org/sqlcomponents/core/crawler/Crawler.java)) centralizes JDBC metadata access: tables, columns, imported/exported keys, indexes, procedures, and more. It recognizes product names such as PostgreSQL, MySQL/MariaDB, H2, Oracle, SQL Server.
- **Dialect-specific classes** (e.g. [`PostgresCrawler`](../core/src/main/java/org/sqlcomponents/core/crawler/PostgresCrawler.java), [`MysqlCrawler`](../core/src/main/java/org/sqlcomponents/core/crawler/MysqlCrawler.java)) extend or specialize behavior where generic metadata is insufficient or dialect-specific SQL is required.

The crawler layer uses **HikariCP** (provided at parent POM level) and standard JDBC types.

## Key types

### `Application`

[`Application`](../core/src/main/java/org/sqlcomponents/core/model/Application.java) is the root configuration object: human-readable name, JDBC URL, credentials, driver, schema, table/sequence include patterns, target `srcFolder`, `rootPackage`, naming maps (`wordsMap`, `modulesMap`, `pluralMap`), insert/update default maps, encryption column lists, and references to `ORM`.

Important behavior:

- **`compile(Compiler)`**: If `srcFolder` exists, it is **deleted recursively** (newest paths first), then `compiler.compile(this)` is invoked. Any implementation must repopulate that directory.

### `ORM`

Holds schema-level ORM settings and the entity graph produced after mapping (see compiler module’s mapper). `Application` delegates many getters/setters to `ORM`.

### `Entity`

Represents one generated unit (typically aligned with a table, view, or enum type), carrying relational metadata and naming used by templates.

### Relational types

Types under `org.sqlcomponents.core.model.relational` mirror JDBC catalog concepts so the compiler can emit Java without re-querying the database during generation.

## Configuration loading (YAML)

[`CoreConsts.buildApplication(File)`](../core/src/main/java/org/sqlcomponents/core/utils/CoreConsts.java) loads an `Application` from a YAML file using SnakeYAML’s `Constructor(Application.class)`, then sets `methodSpecification` to `Application.METHOD_SPECIFICATION` by default.

Compiler tests can instead use properties-based setup via [`CompilerTestUtil`](../compiler/src/test/java/org/sqlcomponents/compiler/java/util/CompilerTestUtil.java) when `SQLCOMPONENTS_CONFIG` is not set.

## Dependencies (`core/pom.xml`)

- **SnakeYAML**: YAML configuration for `Application`.
- **JetBrains annotations**: Nullable/not-null hints for static analysis.

Other JDBC drivers and connection pooling are inherited from the **parent** POM for the whole project; core code expects a JDBC `DataSource` or equivalent when crawling.

## Relationship to the compiler module

The compiler module depends on **core** only. Core does **not** reference FreeMarker or `JavaCompiler`. Generation is triggered by application code calling `application.compile(new JavaCompiler())` (or another `Compiler` implementation).

## Related documentation

- [Compiler module](compiler.md)
- [Datastore module](datastore.md)
- [Project structure](project-structure.md)
- [Documentation index](README.md)
Loading
Loading