Skip to content

Commit 3f557fe

Browse files
Update pgxntool and add docs for Claude (#10)
## Summary - Update pgxntool to latest release - Update .gitignore from pgxntool template (adds control.mk, .claude/*.local.json, /pg_tle/) - Add CLAUDE.md documentation for Claude Code AI assistant
1 parent 3818583 commit 3f557fe

22 files changed

Lines changed: 2790 additions & 322 deletions

.gitignore

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
# Editor files
22
.*.swp
33

4+
# Claude Code local settings
5+
.claude/*.local.json
6+
47
# Explicitly exclude META.json!
58
!/META.json
69

710
# Generated make files
811
meta.mk
12+
control.mk
913

1014
# Compiler output
1115
*.o
1216
*.so
1317
.deps/
1418

1519
# built targets
16-
/sql/*--*
17-
!/sql/*--*--*.sql
20+
# Note: Version-specific files (sql/*--*.sql) are now tracked in git and should be committed
1821

1922
# Test artifacts
2023
results/
@@ -24,3 +27,6 @@ regression.out
2427
# Misc
2528
tmp/
2629
.DS_Store
30+
31+
# pg_tle generated files
32+
/pg_tle/

CLAUDE.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
This is **test_factory**, a PostgreSQL extension that provides a framework for managing unit test data in databases. It solves the common problem of creating and maintaining test data by providing a system to register test data definitions once and retrieve them efficiently with automatic dependency resolution.
8+
9+
## Build System & Development Commands
10+
11+
This project uses PGXNtool for build management. Key commands:
12+
13+
### Building and Installation
14+
```bash
15+
make # Build the extension
16+
make install # Install to PostgreSQL
17+
make clean # Clean build artifacts
18+
make distclean # Clean all generated files including META.json
19+
```
20+
21+
### Testing
22+
```bash
23+
make test # Run full test suite (install, then test)
24+
make installcheck # Run tests only (no clean/install)
25+
make results # Update expected test results (only after verifying tests pass!)
26+
```
27+
28+
### Distribution
29+
```bash
30+
make tag # Create git tag for current version
31+
make dist # Create distribution zip file
32+
make forcetag # Force recreate tag if it exists
33+
make forcedist # Force tag + distribution
34+
```
35+
36+
## Architecture & Key Components
37+
38+
### Core API Functions
39+
- `tf.register(table_name, test_sets[])` - Register test data definitions for a table
40+
- `tf.get(table_type, set_name)` - Retrieve test data, creating it if it doesn't exist
41+
- `tf.tap(table_name, set_name)` - pgTAP integration wrapper for testing
42+
43+
### Database Schema Organization
44+
- `tf` schema: User-facing API (functions, types)
45+
- `_tf` schema: Internal implementation (tables, security definer functions)
46+
- `_test_factory_test_data` schema: Cached test data storage
47+
- Uses dedicated `test_factory__owner` role for security isolation
48+
49+
### Security Model
50+
- Role-based access with `test_factory__owner` for data management
51+
- Security definer functions with `search_path=pg_catalog`
52+
- Proper permission isolation between user and system operations
53+
54+
### Key Data Structures
55+
```sql
56+
CREATE TYPE tf.test_set AS (
57+
set_name text, -- Name to reference this test data set
58+
insert_sql text -- SQL command that returns test data rows
59+
);
60+
```
61+
62+
### Test Data Workflow
63+
1. **Registration**: Use `tf.register()` to define how test data is created
64+
2. **Retrieval**: Call `tf.get()` to obtain test data (creates on first call)
65+
3. **Caching**: Test data is stored permanently for fast subsequent access
66+
4. **Dependencies**: Test sets can reference other test sets via embedded `tf.get()` calls
67+
68+
### Performance & Caching
69+
- Test data created once and cached in permanent tables
70+
- Subsequent `tf.get()` calls return cached data without recreation
71+
- Data remains available even if source tables are modified/truncated
72+
- Dependency resolution handled automatically during creation
73+
74+
## File Structure Key Points
75+
76+
### SQL Files
77+
- `sql/test_factory.sql` and `sql/test_factory--0.5.0.sql`: Main extension code
78+
- Complex role management and schema setup with proper cleanup
79+
- Security definer functions for safe cross-schema operations
80+
81+
### Build Configuration
82+
- `META.in.json`: Template for PGXN metadata (processed to `META.json`)
83+
- `test_factory.control`: PostgreSQL extension control file
84+
- `Makefile`: Simple inclusion of pgxntool's build system
85+
86+
## Development Workflow
87+
88+
1. **Making Changes**: Modify source files in `sql/` directory
89+
2. **Testing**: Run `make test` to ensure all tests pass
90+
3. **Version Updates**: Update version in both `META.in.json` and `test_factory.control`
91+
4. **Distribution**: Use `make dist` to create release packages
92+
93+
## Extension Architecture Details
94+
95+
The extension handles complex bootstrapping during installation:
96+
- Creates temporary role tracking for safe installation
97+
- Sets up three schemas with proper ownership and permissions
98+
- Uses security definer pattern for controlled access to internal functions
99+
- Automatically restores original database role after installation
100+
- Implements dependency resolution through recursive `tf.get()` calls
101+
102+
## Usage Patterns
103+
104+
### Basic Registration
105+
```sql
106+
SELECT tf.register(
107+
'customer',
108+
array[
109+
row('base', 'INSERT INTO customer VALUES (DEFAULT, ''Test'', ''User'') RETURNING *')::tf.test_set
110+
]
111+
);
112+
```
113+
114+
### With Dependencies
115+
```sql
116+
SELECT tf.register(
117+
'invoice',
118+
array[
119+
row('base', 'INSERT INTO invoice VALUES (DEFAULT, (tf.get(NULL::customer, ''base'')).customer_id, current_date) RETURNING *')::tf.test_set
120+
]
121+
);
122+
```
123+
124+
### Data Retrieval
125+
```sql
126+
-- Gets customer test data, creating it if needed
127+
SELECT * FROM tf.get(NULL::customer, 'base');
128+
129+
-- Gets invoice test data, automatically creating dependent customer data
130+
SELECT * FROM tf.get(NULL::invoice, 'base');
131+
```
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
description: Create a git commit following project standards and safety protocols
3+
allowed-tools: Bash(git status:*), Bash(git log:*), Bash(git add:*), Bash(git diff:*), Bash(git commit:*), Bash(make test:*)
4+
---
5+
6+
# commit
7+
8+
Create a git commit following all project standards and safety protocols for pgxntool-test.
9+
10+
**CRITICAL REQUIREMENTS:**
11+
12+
1. **Git Safety**: Never update `git config`, never force push to `main`/`master`, never skip hooks unless explicitly requested
13+
14+
2. **Commit Attribution**: Do NOT add "Generated with Claude Code" to commit message body. The standard Co-Authored-By trailer is acceptable per project CLAUDE.md.
15+
16+
3. **Testing**: ALL tests must pass before committing:
17+
- Run `make test`
18+
- Check the output carefully for any "not ok" lines
19+
- Count passing vs total tests
20+
- **If ANY tests fail: STOP. Do NOT commit. Ask the user what to do.**
21+
- There is NO such thing as an "acceptable" failing test
22+
- Do NOT rationalize failures as "pre-existing" or "unrelated"
23+
24+
**WORKFLOW:**
25+
26+
1. Run in parallel: `git status`, `git diff --stat`, `git log -10 --oneline`
27+
28+
2. Check test status - THIS IS MANDATORY:
29+
- Run `make test 2>&1 | tee /tmp/test-output.txt`
30+
- Check for failing tests: `grep "^not ok" /tmp/test-output.txt`
31+
- If ANY tests fail: STOP immediately and inform the user
32+
- Only proceed if ALL tests pass
33+
34+
3. Analyze changes and draft concise commit message following this repo's style:
35+
- Look at `git log -10 --oneline` to match existing style
36+
- Be factual and direct (e.g., "Fix BATS dist test to create its own distribution")
37+
- Focus on "why" when it adds value, otherwise just describe "what"
38+
- List items in roughly decreasing order of impact
39+
- Keep related items grouped together
40+
- **In commit messages**: Wrap all code references in backticks - filenames, paths, commands, function names, variables, make targets, etc.
41+
- Examples: `helpers.bash`, `make test-recursion`, `setup_sequential_test()`, `TEST_REPO`, `.envs/`, `01-meta.bats`
42+
- Prevents markdown parsing issues and improves clarity
43+
44+
4. **PRESENT the proposed commit message to the user and WAIT for approval before proceeding**
45+
46+
5. After receiving approval, stage changes appropriately using `git add`
47+
48+
6. **VERIFY staged files with `git status`**:
49+
- If user did NOT specify a subset: Confirm ALL modified/untracked files are staged
50+
- If user specified only certain files: Confirm ONLY those files are staged
51+
- STOP and ask user if staging doesn't match intent
52+
53+
7. After verification, commit using `HEREDOC` format:
54+
```bash
55+
git commit -m "$(cat <<'EOF'
56+
Subject line (imperative mood, < 72 chars)
57+
58+
Additional context if needed, wrapped at 72 characters.
59+
60+
Co-Authored-By: Claude <noreply@anthropic.com>
61+
EOF
62+
)"
63+
```
64+
65+
8. Run `git status` after commit to verify success
66+
67+
9. If pre-commit hook modifies files: Check authorship (`git log -1 --format='%an %ae'`) and branch status, then amend if safe or create new commit
68+
69+
**REPOSITORY CONTEXT:**
70+
71+
This is pgxntool-test, a test harness for the pgxntool framework. Key facts:
72+
- Tests live in `tests/` directory
73+
- `.envs/` contains test environments (gitignored)
74+
75+
**RESTRICTIONS:**
76+
- DO NOT push unless explicitly asked
77+
- DO NOT commit files with actual secrets (`.env`, `credentials.json`, etc.)
78+
- Never use `-i` flags (`git commit -i`, `git rebase -i`, etc.)

pgxntool/.claude/settings.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(cat:*)",
5+
"Bash(make test:*)",
6+
"Bash(tee:*)",
7+
"Bash(echo:*)",
8+
"Bash(git show:*)",
9+
"Bash(git log:*)",
10+
"Bash(ls:*)",
11+
"Bash(find:*)",
12+
"Bash(git checkout:*)",
13+
"Bash(head:*)"
14+
],
15+
"additionalDirectories": [
16+
"../pgxntool-test/"
17+
]
18+
}
19+
}

pgxntool/.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
.gitattributes export-ignore
2+
.claude/ export-ignore
3+
*.md export-ignore
4+
.DS_Store export-ignore
25
*.asc export-ignore
36
*.adoc export-ignore
47
*.html export-ignore

pgxntool/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
.*.swp
2+
.claude/*.local.json

0 commit comments

Comments
 (0)