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
68 changes: 49 additions & 19 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,16 @@ my-app/
├── pom.xml
├── sqlcj.yaml
├── sql/
│ ├── queries.sql
│ └── schema.sql
│ ├── migrations/
│ │ ├── V1__create_authors_and_books.sql
│ │ └── V2__add_author_created_at_and_book_index.sql
│ └── queries.sql
├── src/main/java/com/example/app/App.java
└── tools/sqlcj-cli-0.1.0-SNAPSHOT.jar
```

```bash
mkdir -p sql src/main/java/com/example/app
mkdir -p sql/migrations src/main/java/com/example/app
```

## 4. `pom.xml`
Expand Down Expand Up @@ -140,7 +142,7 @@ Two details matter:
version: "1"
sql:
- name: Author
schema: sql/schema.sql
schema: sql/migrations
queries: sql/queries.sql
java:
package: com.example.app.db
Expand All @@ -157,18 +159,19 @@ relative paths above are resolved against the directory that contains the file.
Generated output therefore belongs in the build directory, where `mvn clean`
removes it. See [Configuration](configuration.md) for the full file format.

## 6. `sql/schema.sql`
## 6. `sql/migrations`

The schema file is a snapshot of the tables the queries use. sqlcj reads it; it
never runs it.
The configured schema is a migration directory rather than one snapshot file.
sqlcj reads its files; it never runs them.

`sql/migrations/V1__create_authors_and_books.sql`:

```sql
CREATE TABLE authors
(
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
bio TEXT,
created_at TIMESTAMP
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
bio TEXT
);

CREATE TABLE books
Expand All @@ -179,7 +182,29 @@ CREATE TABLE books
);
```

The accepted column types and `CREATE TABLE` constructs are listed in
`sql/migrations/V2__add_author_created_at_and_book_index.sql`:

```sql
ALTER TABLE authors ADD COLUMN created_at TIMESTAMP;

CREATE INDEX books_author_id_idx ON books (author_id);
```

A directory named by `sql[].schema` is read in Flyway version order, so `V1`
comes before `V2` no matter how the filesystem lists the two files. The
statements of both files build one schema model: `V2` applies its
`ALTER TABLE ... ADD COLUMN` to the `authors` table `V1` created, appending
`created_at` after `bio`, and its `CREATE INDEX` is accepted and ignored,
because an index changes no column the queries can read. The modeled tables are
therefore exactly the two tables the queries use, with `authors` carrying `id`,
`name`, `bio`, and `created_at` in that order.

See [`sql[].schema`](configuration.md#sqlschema) for the directory and ordering
rules, [Ordered Table DDL](postgresql.md#ordered-table-ddl) for the statements
that update an already modeled table, and
[Ignored Statements](postgresql.md#ignored-statements) for the statements that
are accepted without changing the model. The accepted column types and
`CREATE TABLE` constructs are listed in
[PostgreSQL Support](postgresql.md).

## 7. `sql/queries.sql`
Expand Down Expand Up @@ -381,7 +406,7 @@ One repository instance serves the whole `DataSource`-backed execution context,
and each transaction constructs another repository over its caller-owned
connection. No code constructs a type per query.

## 9. Start PostgreSQL and apply the schema
## 9. Start PostgreSQL and apply the migrations

```bash
docker run --rm -d --name sqlcj-quickstart \
Expand All @@ -391,13 +416,17 @@ docker run --rm -d --name sqlcj-quickstart \
-p 5432:5432 \
postgres:16-alpine

docker exec -i sqlcj-quickstart psql -U quickstart -d quickstart < sql/schema.sql
docker exec -i sqlcj-quickstart psql -U quickstart -d quickstart \
< sql/migrations/V1__create_authors_and_books.sql
docker exec -i sqlcj-quickstart psql -U quickstart -d quickstart \
< sql/migrations/V2__add_author_created_at_and_book_index.sql
```

sqlcj does not create or migrate tables. Applying the same snapshot text that
the compiler reads initializes the walkthrough database consistently with the
compiler's input. sqlcj never inspects the live database, so keeping the
snapshot synchronized with later database changes is your responsibility.
sqlcj reads the migration files and never runs them. Applying them is the job of
the application's migration tool, which is `psql` in the two commands above, run
in the same version order sqlcj reads them in. sqlcj never inspects the live
database, so keeping the migration directory the compiler reads and the database
the application connects to in step is your responsibility.

## 10. Generate, compile, and run

Expand Down Expand Up @@ -493,7 +522,8 @@ That output is the whole MVP contract in one run:

## 11. Re-running after a SQL change

After editing `sql/schema.sql` or `sql/queries.sql`, repeat the same order:
After adding a migration under `sql/migrations` or editing `sql/queries.sql`,
repeat the same order:

```bash
mvn clean
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
CREATE TABLE authors
(
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
bio TEXT,
created_at TIMESTAMP
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
bio TEXT
);

CREATE TABLE books
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALTER TABLE authors ADD COLUMN created_at TIMESTAMP;

CREATE INDEX books_author_id_idx ON books (author_id);
2 changes: 1 addition & 1 deletion examples/maven-postgresql/sqlcj.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: "1"
sql:
- name: Author
schema: sql/schema.sql
schema: sql/migrations
queries: sql/queries.sql
java:
package: com.example.app.db
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@
* <p>Every step is checked, so the process exits non-zero as soon as one
* generated operation returns an unexpected result.
*
* <p>The verification harness applies {@code sql/schema.sql} to empty
* {@code authors} and {@code books} tables before this application runs.
* <p>The verification harness applies the {@code sql/migrations} files in
* version order to empty {@code authors} and {@code books} tables before this
* application runs.
*/
public final class App {

Expand Down
18 changes: 11 additions & 7 deletions scripts/verify-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ sample_mvn() {
"$@"
}

command -v psql >/dev/null 2>&1 || fail "psql is required to apply the sample schema"
command -v psql >/dev/null 2>&1 || fail "psql is required to apply the sample migrations"

log "Staging the reactor into ${local_repo}"

Expand Down Expand Up @@ -160,10 +160,10 @@ cat > "${regeneration_dir}/author-and-library.yaml" <<'YAML'
version: "1"
sql:
- name: Author
schema: ../sample/sql/schema.sql
schema: ../sample/sql/migrations
queries: ../sample/sql/queries.sql
- name: Library
schema: ../sample/sql/schema.sql
schema: ../sample/sql/migrations
queries: ../sample/sql/queries.sql
java:
package: com.example.app.db
Expand All @@ -174,7 +174,7 @@ cat > "${regeneration_dir}/writer.yaml" <<'YAML'
version: "1"
sql:
- name: Writer
schema: ../sample/sql/schema.sql
schema: ../sample/sql/migrations
queries: ../sample/sql/queries.sql
java:
package: com.example.app.db
Expand Down Expand Up @@ -230,6 +230,9 @@ for method in createAuthor getAuthor findAuthor listAuthors updateAuthorBio dele
|| fail "the generated repository is missing the ${method} method"
done

grep -q "LocalDateTime createdAt" "${generated_package}/AuthorRepository.java" \
|| fail "the generated row is missing the column the second migration adds"

diff -r "${first_generation}" "${generated_root}" \
|| fail "generating from the sample directory did not restore its first generated output"

Expand All @@ -251,16 +254,17 @@ fi

tr ':' '\n' < "${classpath_file}"

log "Applying the sample schema to ${jdbc_url}"
log "Applying the sample migrations to ${jdbc_url}"

# psql accepts the JDBC URL as a connection URI once the 'jdbc:' prefix is
# removed, so the sample and the schema reset share one setting.
# removed, so the sample and the migration reset share one setting.
PGPASSWORD="${db_password}" psql \
--set=ON_ERROR_STOP=1 \
--quiet \
--username "${db_user}" \
--command 'DROP TABLE IF EXISTS books, authors;' \
--file "${sample_dir}/sql/schema.sql" \
--file "${sample_dir}/sql/migrations/V1__create_authors_and_books.sql" \
--file "${sample_dir}/sql/migrations/V2__add_author_created_at_and_book_index.sql" \
"${jdbc_url#jdbc:}"

log "Compiling the sample against the staged runtime"
Expand Down
Loading