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
33 changes: 33 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,39 @@ open target/site/jacoco/index.html
- Exception hierarchy: `QueryBuilderException` → `QueryException` / `QueryRenderException` in `query.exception`
- Test class names match source class names with `Test` suffix and live in the same sub-package under `src/test/`

## Agent Planning

For multi-step tasks the agent maintains a visible todo list to track progress. Each item moves through three states: `not-started` → `in-progress` → `completed`. Only one item is in-progress at a time; it is marked completed immediately when done.

**Typical workflow for a non-trivial request**:

1. **Gather context** — read relevant source files and tests in parallel.
2. **Plan** — break the work into concrete, ordered todos (e.g., add operator → update builder → write tests → verify build).
3. **Execute** — work through todos one at a time, updating state as each finishes.
4. **Validate** — run `mvn checkstyle:check` and `mvn test` after changes; fix any failures before marking the task complete.

**When planning is skipped**: trivial, single-step requests (e.g., "what does `Operator.EQ` do?") do not need a todo list.

**Communicating with the agent**: if you want the agent to change direction mid-task, just say so — it will update the plan and continue from the new state.

## Agent Memory

Copilot agents can persist project-scoped notes in `/memories/repo/` to carry context across sessions. Use this to record verified facts about the codebase so they don't need to be re-discovered.

**Create a repo memory note** (only `create` is supported for this path):

> "Remember that the `Query` class is immutable and built exclusively via the builder classes."

The agent will store this under `/memories/repo/` and load it automatically in future sessions.

**Useful things to store**:
- Verified build commands and their quirks
- Project-specific conventions not obvious from the code
- Known gotchas (e.g., "always run `mvn checkstyle:check` before committing")
- Architecture decisions and their rationale

**Scope**: repo memory is local to this workspace and is never shared or published.

## Packaging and Distribution

- **GitHub Packages**: published automatically on GitHub Release creation via [.github/workflows/publish.yml](.github/workflows/publish.yml)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package com.github.ezframework.javaquerybuilder.query.builder;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.github.ezframework.javaquerybuilder.query.sql.SqlDialect;
import com.github.ezframework.javaquerybuilder.query.sql.SqlResult;

/**
* Builder for SQL CREATE TABLE statements.
*
* @author EzFramework
* @version 1.0.0
*/
public class CreateBuilder {

/** The table to create. */
private String table;

/** The columns and their SQL types. */
private final Map<String, String> columns = new LinkedHashMap<>();

/** The primary key columns. */
private final List<String> primaryKeys = new ArrayList<>();

/** Whether to add IF NOT EXISTS. */
private boolean ifNotExists = false;

/**
* Sets the table to create.
* @param table the table name
* @return this builder
*/
public CreateBuilder table(String table) {
this.table = table;
return this;
}

/**
* Adds a column definition.
* @param name the column name
* @param sqlType the SQL type (e.g. "VARCHAR(255)", "INT")
* @return this builder
*/
public CreateBuilder column(String name, String sqlType) {
columns.put(name, sqlType);
return this;
}

/**
* Adds a primary key column.
* @param name the column name
* @return this builder
*/
public CreateBuilder primaryKey(String name) {
primaryKeys.add(name);
return this;
}

/**
* Adds IF NOT EXISTS to the statement.
* @return this builder
*/
public CreateBuilder ifNotExists() {
this.ifNotExists = true;
return this;
}

/**
* Builds the SQL CREATE TABLE statement.
*
* @return the SQL result
* @throws IllegalStateException if table name or columns are missing
*/
public SqlResult build() {
return build(null);
}

/**
* Builds the SQL CREATE TABLE statement using the given dialect.
*
* @param dialect the SQL dialect to use; if {@code null}, the standard dialect is used
* @return the SQL result
* @throws IllegalStateException if table name or columns are missing
*/
public SqlResult build(SqlDialect dialect) {
if (table == null || columns.isEmpty()) {
throw new IllegalStateException("Table name and at least one column are required");
}
final StringBuilder sql = new StringBuilder();
sql.append("CREATE TABLE ");
if (ifNotExists) {
sql.append("IF NOT EXISTS ");
}
sql.append(table).append(" (");
boolean first = true;
for (Map.Entry<String, String> entry : columns.entrySet()) {
if (!first) {
sql.append(", ");
}
sql.append(entry.getKey()).append(" ").append(entry.getValue());
first = false;
}
if (!primaryKeys.isEmpty()) {
sql.append(", PRIMARY KEY (");
sql.append(String.join(", ", primaryKeys));
sql.append(")");
}
sql.append(")");

return new SqlResult() {
@Override
public String getSql() {
return sql.toString();
}

@Override
public List<Object> getParameters() {
return List.of();
}
};
}
}
Loading
Loading