init
Some checks are pending
CI / Test (1.23) (push) Waiting to run
CI / Test (1.24) (push) Waiting to run
CI / Test (1.25) (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Build (push) Waiting to run

This commit is contained in:
2025-12-16 13:12:43 +02:00
parent 9f42be432b
commit b9650739bf
20 changed files with 1095 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
---
description: Build the RelSpec binary
---
Build the RelSpec project by running `go build -o relspec ./cmd/relspec`. Report the build status and any errors encountered.

View File

@@ -0,0 +1,9 @@
---
description: Generate test coverage report
---
Generate and display test coverage for RelSpec:
1. Run `go test -cover ./...` to get coverage percentage
2. If detailed coverage is needed, run `go test -coverprofile=coverage.out ./...` and then `go tool cover -html=coverage.out` to generate HTML report
Show coverage statistics and identify areas needing more tests.

10
.claude/commands/lint.md Normal file
View File

@@ -0,0 +1,10 @@
---
description: Run Go linters on the codebase
---
Run linting tools on the RelSpec codebase:
1. First run `gofmt -l .` to check formatting
2. If golangci-lint is available, run `golangci-lint run ./...`
3. Run `go vet ./...` to check for suspicious constructs
Report any issues found and suggest fixes if needed.

5
.claude/commands/test.md Normal file
View File

@@ -0,0 +1,5 @@
---
description: Run all tests for the RelSpec project
---
Run `go test ./...` to execute all unit tests in the project. Show a summary of the results and highlight any failures.

25
.claude/settings.json Normal file
View File

@@ -0,0 +1,25 @@
{
"project": {
"name": "RelSpec",
"description": "Database Relations Specification Tool for Go",
"language": "go"
},
"agent": {
"preferred": "Explore",
"description": "Use Explore agent for fast codebase navigation and Go project exploration"
},
"codeStyle": {
"useGofmt": true,
"lineLength": 100,
"tabWidth": 4,
"useTabs": true
},
"testing": {
"framework": "go test",
"runOnChange": false
},
"build": {
"command": "go build -o relspec ./cmd/relspec",
"outputBinary": "relspec"
}
}

39
.editorconfig Normal file
View File

@@ -0,0 +1,39 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
# Go files
[*.go]
indent_style = tab
indent_size = 4
# YAML files
[*.{yml,yaml}]
indent_style = space
indent_size = 2
# JSON files
[*.json]
indent_style = space
indent_size = 2
# Markdown files
[*.md]
trim_trailing_whitespace = false
# Makefile
[Makefile]
indent_style = tab
# Shell scripts
[*.sh]
indent_style = space
indent_size = 2

85
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,85 @@
name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.23', '1.24', '1.25']
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Cache Go modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Download dependencies
run: go mod download
- name: Run tests
run: go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.out
flags: unittests
name: codecov-umbrella
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: latest
args: --config=.golangci.json
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: Build
run: go build -v ./cmd/relspec
- name: Check mod tidiness
run: |
go mod tidy
git diff --exit-code go.mod go.sum

26
.gitignore vendored
View File

@@ -21,3 +21,29 @@
# Go workspace file
go.work
# RelSpec specific
relspec
*.test
coverage.out
coverage.html
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Test outputs
test_output/
*.db
*.sqlite
*.sqlite3
# Build artifacts
dist/
build/

114
.golangci.json Normal file
View File

@@ -0,0 +1,114 @@
{
"formatters": {
"enable": [
"gofmt",
"goimports"
],
"exclusions": {
"generated": "lax",
"paths": [
"third_party$",
"builtin$",
"examples$"
]
},
"settings": {
"gofmt": {
"simplify": true
},
"goimports": {
"local-prefixes": [
"git.warky.dev/wdevs/relspecgo"
]
}
}
},
"issues": {
"max-issues-per-linter": 0,
"max-same-issues": 0
},
"linters": {
"enable": [
"gocritic",
"misspell",
"revive"
],
"exclusions": {
"generated": "lax",
"paths": [
"third_party$",
"builtin$",
"examples$",
"mocks?",
"tests?"
],
"rules": [
{
"linters": [
"dupl",
"errcheck",
"gocritic",
"gosec"
],
"path": "_test\\.go"
},
{
"linters": [
"errcheck"
],
"text": "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked"
},
{
"path": "_test\\.go",
"text": "cognitive complexity|cyclomatic complexity"
}
]
},
"settings": {
"errcheck": {
"check-blank": false,
"check-type-assertions": false
},
"gocritic": {
"enabled-checks": [
"boolExprSimplify",
"builtinShadow",
"emptyFallthrough",
"equalFold",
"indexAlloc",
"initClause",
"methodExprCall",
"nilValReturn",
"rangeExprCopy",
"rangeValCopy",
"stringXbytes",
"typeAssertChain",
"unlabelStmt",
"unnamedResult",
"unnecessaryBlock",
"weakCond",
"yodaStyleExpr"
],
"disabled-checks": [
"ifElseChain"
]
},
"revive": {
"rules": [
{
"disabled": true,
"name": "exported"
},
{
"disabled": true,
"name": "package-comments"
}
]
}
}
},
"run": {
"tests": true
},
"version": "2"
}

145
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,145 @@
# Contributing to RelSpec
Thank you for your interest in contributing to RelSpec.
## Development Setup
### Prerequisites
- Go 1.21 or higher
- Git
- (Optional) golangci-lint for linting
- (Optional) Docker for database testing
### Getting Started
1. Clone the repository:
```bash
git clone https://github.com/wdevs/relspecgo.git
cd relspecgo
```
2. Install dependencies:
```bash
go mod download
```
3. Run tests:
```bash
go test ./...
```
4. Build the project:
```bash
go build -o relspec ./cmd/relspec
```
## Project Structure
```
relspecgo/
├── cmd/ # CLI application entry point
├── pkg/
│ ├── readers/ # Input format readers (XML, JSON, DCTX, DB, GORM, Bun)
│ ├── writers/ # Output format writers (GORM, Bun, JSON, YAML)
│ ├── models/ # Internal data models for relations
│ └── transform/ # Transformation and validation logic
├── examples/ # Usage examples and sample files
├── tests/ # Integration tests
└── .claude/ # Claude Code configuration and commands
```
## Adding New Readers
To add a new input format reader:
1. Create a new file in `pkg/readers/` (e.g., `myformat_reader.go`)
2. Implement the `Reader` interface:
```go
type Reader interface {
Read(source string) (*models.Schema, error)
}
```
3. Add tests in `pkg/readers/myformat_reader_test.go`
4. Register the reader in the CLI
## Adding New Writers
To add a new output format writer:
1. Create a new file in `pkg/writers/` (e.g., `myformat_writer.go`)
2. Implement the `Writer` interface:
```go
type Writer interface {
Write(schema *models.Schema, destination string) error
}
```
3. Add tests in `pkg/writers/myformat_writer_test.go`
4. Register the writer in the CLI
## Code Style
- Follow standard Go conventions
- Use `gofmt` for formatting
- Run `go vet` to check for issues
- Use meaningful variable and function names
- Add comments for exported functions and types
## Testing
- Write unit tests for all new functionality
- Aim for >80% code coverage
- Use table-driven tests where appropriate
- Include both positive and negative test cases
### Running Tests
```bash
# All tests
go test ./...
# With coverage
go test -cover ./...
# Verbose output
go test -v ./...
# Specific package
go test ./pkg/readers/...
```
## Committing Changes
- Write clear, descriptive commit messages
- Follow conventional commits format: `type(scope): description`
- Types: feat, fix, docs, test, refactor, chore
- Example: `feat(readers): add PostgreSQL support`
- Keep commits focused and atomic
- Reference issues in commit messages when applicable
## Pull Request Process
1. Create a feature branch from `master`
2. Make your changes
3. Add tests for new functionality
4. Ensure all tests pass
5. Update documentation if needed
6. Submit a pull request with a clear description
## Claude Code Commands
This project includes Claude Code slash commands for common tasks:
- `/test` - Run all tests
- `/build` - Build the binary
- `/lint` - Run linters
- `/coverage` - Generate coverage report
## Questions or Issues?
- Open an issue for bugs or feature requests
- Start a discussion for questions or ideas
- Check existing issues before creating new ones
## License
By contributing to RelSpec, you agree that your contributions will be licensed under the Apache License 2.0.

62
Makefile Normal file
View File

@@ -0,0 +1,62 @@
.PHONY: all build test lint coverage clean install help
# Binary name
BINARY_NAME=relspec
# Build directory
BUILD_DIR=build
# Go parameters
GOCMD=go
GOBUILD=$(GOCMD) build
GOTEST=$(GOCMD) test
GOGET=$(GOCMD) get
GOMOD=$(GOCMD) mod
GOCLEAN=$(GOCMD) clean
all: lint test build ## Run linting, tests, and build
build: ## Build the binary
@echo "Building $(BINARY_NAME)..."
@mkdir -p $(BUILD_DIR)
$(GOBUILD) -o $(BUILD_DIR)/$(BINARY_NAME) ./cmd/relspec
@echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME)"
test: ## Run tests
@echo "Running tests..."
$(GOTEST) -v -race -coverprofile=coverage.out ./...
coverage: test ## Run tests with coverage report
@echo "Generating coverage report..."
$(GOCMD) tool cover -html=coverage.out -o coverage.html
@echo "Coverage report generated: coverage.html"
lint: ## Run linter
@echo "Running linter..."
@if command -v golangci-lint > /dev/null; then \
golangci-lint run --config=.golangci.json; \
else \
echo "golangci-lint not installed. Install with: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
exit 1; \
fi
clean: ## Clean build artifacts
@echo "Cleaning..."
$(GOCLEAN)
rm -rf $(BUILD_DIR)
rm -f coverage.out coverage.html
@echo "Clean complete"
install: ## Install the binary to $GOPATH/bin
@echo "Installing $(BINARY_NAME)..."
$(GOCMD) install ./cmd/relspec
@echo "Install complete"
deps: ## Download dependencies
@echo "Downloading dependencies..."
$(GOMOD) download
$(GOMOD) tidy
@echo "Dependencies updated"
help: ## Display this help screen
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'

View File

@@ -1,3 +1,93 @@
# relspecgo
# RelSpec
Resolve Spec Go
> Database Relations Specification Tool for Go
RelSpec is a comprehensive database relations management tool that reads, transforms, and writes database table specifications across multiple formats and ORMs.
## Overview
RelSpec provides bidirectional conversion between various database specification formats, allowing you to:
- Inspect live databases and extract their structure
- Convert between different ORM models (GORM, Bun)
- Transform legacy schema definitions (Clarion DCTX, XML, JSON)
- Generate standardized specification files (JSON, YAML)
## Features
### Input Formats
- **XML** - Generic XML schema definitions
- **JSON** - JSON-based schema specifications
- **Clarion DCTX** - Clarion database dictionary format
- **Database Inspection** - Direct database introspection
- **GORM Models** - Read existing GORM Go structs
- **Bun Models** - Read existing Bun Go structs
### Output Formats
- **GORM Models** - Generate GORM-compatible Go structs
- **Bun Models** - Generate Bun-compatible Go structs
- **JSON** - Standard JSON schema output
- **YAML** - Human-readable YAML format
## Installation
```bash
go get github.com/wdevs/relspecgo
```
## Usage
```bash
# Inspect database and generate GORM models
relspec --input db --conn "postgres://..." --output gorm --out-file models.go
# Convert GORM models to Bun
relspec --input gorm --in-file existing.go --output bun --out-file bun_models.go
# Export database schema to JSON
relspec --input db --conn "mysql://..." --output json --out-file schema.json
# Convert Clarion DCTX to YAML
relspec --input dctx --in-file legacy.dctx --output yaml --out-file schema.yaml
```
## Project Structure
```
relspecgo/
├── cmd/ # CLI application
├── pkg/
│ ├── readers/ # Input format readers
│ ├── writers/ # Output format writers
│ ├── models/ # Internal data models
│ └── transform/ # Transformation logic
├── examples/ # Usage examples
└── tests/ # Test files
```
## Development
### Prerequisites
- Go 1.21 or higher
- Access to test databases (optional)
### Building
```bash
go build -o relspec ./cmd/relspec
```
### Testing
```bash
go test ./...
```
## License
Apache License 2.0 - See [LICENSE](LICENSE) for details.
Copyright 2025 wdevs
## Contributing
Contributions welcome. Please open an issue or submit a pull request.

120
TODO.md Normal file
View File

@@ -0,0 +1,120 @@
# RelSpec - TODO List
## Project Setup
- [ ] Initialize Go module (`go.mod`)
- [ ] Set up project directory structure
- [ ] Create `.editorconfig` for consistent formatting
- [ ] Add GitHub Actions for CI/CD
- [ ] Set up pre-commit hooks
## Core Infrastructure
- [ ] Define internal data model for database relations
- [ ] Implement relation types (one-to-one, one-to-many, many-to-many)
- [ ] Create validation framework for specifications
- [ ] Design plugin architecture for readers/writers
## Input Readers
- [ ] **Database Inspector**
- [ ] PostgreSQL driver
- [ ] MySQL driver
- [ ] SQLite driver
- [ ] MSSQL driver
- [ ] Foreign key detection
- [ ] Index extraction
- [ ] **XML Reader**
- [ ] XML schema parser
- [ ] Validation against XSD
- [ ] **JSON Reader**
- [ ] JSON schema parser
- [ ] Schema validation
- [ ] **Clarion DCTX Reader**
- [ ] DCTX file parser
- [ ] Legacy format support
- [ ] **GORM Model Reader**
- [ ] Go AST parser for GORM tags
- [ ] Struct field analysis
- [ ] Relation tag extraction
- [ ] **Bun Model Reader**
- [ ] Go AST parser for Bun tags
- [ ] Struct field analysis
- [ ] Relation tag extraction
## Output Writers
- [ ] **GORM Writer**
- [ ] Go struct generation
- [ ] GORM tag formatting
- [ ] Relation definitions
- [ ] gofmt integration
- [ ] **Bun Writer**
- [ ] Go struct generation
- [ ] Bun tag formatting
- [ ] Relation definitions
- [ ] gofmt integration
- [ ] **JSON Writer**
- [ ] Schema serialization
- [ ] Pretty printing
- [ ] **YAML Writer**
- [ ] Schema serialization
- [ ] Comment preservation
## CLI Application
- [ ] Command-line interface using cobra
- [ ] Input format flags
- [ ] Output format flags
- [ ] Connection string handling
- [ ] File I/O operations
- [ ] Progress indicators
- [ ] Error handling and reporting
- [ ] Configuration file support
## Testing
- [ ] Unit tests for each reader
- [ ] Unit tests for each writer
- [ ] Integration tests for conversion pipelines
- [ ] Test fixtures for all formats
- [ ] Database test containers
- [ ] Benchmark tests for large schemas
## Documentation
- [ ] API documentation (godoc)
- [ ] Usage examples for each format combination
- [ ] Migration guides
- [ ] Architecture documentation
- [ ] Contributing guidelines
## Advanced Features
- [ ] Dry-run mode for validation
- [ ] Diff tool for comparing specifications
- [ ] Migration script generation
- [ ] Custom type mapping configuration
- [ ] Batch processing support
- [ ] Watch mode for auto-regeneration
## Performance
- [ ] Concurrent processing for multiple tables
- [ ] Streaming for large databases
- [ ] Memory optimization
- [ ] Caching layer for repeated operations
## Quality & Maintenance
- [ ] Linting with golangci-lint
- [ ] Code coverage > 80%
- [ ] Security scanning
- [ ] Dependency updates automation
- [ ] Release automation
## Future Considerations
- [ ] Web UI for visual editing
- [ ] REST API server mode
- [ ] Support for NoSQL databases
- [ ] GraphQL schema generation
- [ ] Prisma schema support
- [ ] TypeORM support

22
go.mod Normal file
View File

@@ -0,0 +1,22 @@
module git.warky.dev/wdevs/relspecgo
go 1.25.5
require (
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/cobra v1.10.2 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/spf13/viper v1.21.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.28.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

36
go.sum Normal file
View File

@@ -0,0 +1,36 @@
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

71
make_release.sh Normal file
View File

@@ -0,0 +1,71 @@
#!/bin/bash
# Ask if the user wants to make a release version
read -p "Do you want to make a release version? (y/n): " make_release
if [[ $make_release =~ ^[Yy]$ ]]; then
# Get the latest tag from git
latest_tag=$(git describe --tags --abbrev=0 2>/dev/null)
if [ -z "$latest_tag" ]; then
# No tags exist yet, start with v1.0.0
suggested_version="v1.0.0"
echo "No existing tags found. Starting with $suggested_version"
else
echo "Latest tag: $latest_tag"
# Remove 'v' prefix if present
version_number="${latest_tag#v}"
# Split version into major.minor.patch
IFS='.' read -r major minor patch <<< "$version_number"
# Increment patch version
patch=$((patch + 1))
# Construct new version
suggested_version="v${major}.${minor}.${patch}"
echo "Suggested next version: $suggested_version"
fi
# Ask the user for the version number with the suggested version as default
read -p "Enter the version number (press Enter for $suggested_version): " version
# Use suggested version if user pressed Enter without input
if [ -z "$version" ]; then
version="$suggested_version"
fi
# Prepend 'v' to the version if it doesn't start with it
if ! [[ $version =~ ^v ]]; then
version="v$version"
fi
# Get commit logs since the last tag
if [ -z "$latest_tag" ]; then
# No previous tag, get all commits
commit_logs=$(git log --pretty=format:"- %s" --no-merges)
else
# Get commits since the last tag
commit_logs=$(git log "${latest_tag}..HEAD" --pretty=format:"- %s" --no-merges)
fi
# Create the tag message
if [ -z "$commit_logs" ]; then
tag_message="Release $version"
else
tag_message="Release $version
${commit_logs}"
fi
# Create an annotated tag with the commit logs
git tag -a "$version" -m "$tag_message"
# Push the tag to the remote repository
git push origin "$version"
echo "Tag $version created and pushed to the remote repository."
else
echo "No release version created."
fi

149
pkg/models/models.go Normal file
View File

@@ -0,0 +1,149 @@
package models
type DatabaseType string
const (
PostgresqlDatabaseType DatabaseType = "pgsql"
MSSQLDatabaseType DatabaseType = "mssql"
SqlLiteDatabaseType DatabaseType = "sqlite"
)
// Database represents the complete database schema
type Database struct {
Name string `json:"name" yaml:"name"`
Schemas []*Schema `json:"schemas" yaml:"schemas" xml:"schemas"`
Comment string `json:"comment,omitempty" yaml:"comment,omitempty" xml:"comment,omitempty"`
DatabaseType DatabaseType `json:"database_type,omitempty" yaml:"database_type,omitempty" xml:"database_type,omitempty"`
DatabaseVersion string `json:"database_version,omitempty" yaml:"database_version,omitempty" xml:"database_version,omitempty"`
}
type Schema struct {
Name string `json:"name" yaml:"name" xml:"name"`
Tables []*Table `json:"tables" yaml:"tables" xml:"-"`
Owner string `json:"owner" yaml:"owner" xml:"owner"`
Permissions map[string]string `json:"permissions,omitempty" yaml:"permissions,omitempty" xml:"-"`
Comment string `json:"comment,omitempty" yaml:"comment,omitempty" xml:"comment,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty" yaml:"metadata,omitempty" xml:"-"`
Scripts []*Script `json:"scripts,omitempty" yaml:"scripts,omitempty" xml:"scripts,omitempty"`
}
type Table struct {
Name string `json:"name" yaml:"name" xml:"name"`
Schema string `json:"schema" yaml:"schema" xml:"schema"`
Columns map[string]*Column `json:"columns" yaml:"columns" xml:"-"`
Constraints map[string]*Constraint `json:"constraints" yaml:"constraints" xml:"-"`
Indexes map[string]*Index `json:"indexes,omitempty" yaml:"indexes,omitempty" xml:"-"`
Relationships map[string]*Relationship `json:"relationships,omitempty" yaml:"relationships,omitempty" xml:"-"`
Comment string `json:"comment,omitempty" yaml:"comment,omitempty" xml:"comment,omitempty"`
Tablespace string `json:"tablespace,omitempty" yaml:"tablespace,omitempty" xml:"tablespace,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty" yaml:"metadata,omitempty" xml:"-"`
}
func (m Table) GetPrimaryKey() *Column {
for _, column := range m.Columns {
if column.IsPrimaryKey {
return column
}
}
return nil
}
func (m Table) GetForeignKeys() []*Constraint {
keys := make([]*Constraint, 0)
for _, c := range m.Constraints {
if c.Type == ForeignKeyConstraint {
keys = append(keys, c)
}
}
return keys
}
// Column represents a table column
type Column struct {
Name string `json:"name" yaml:"name" xml:"name"`
Table string `json:"table" yaml:"table" xml:"table"`
Schema string `json:"schema" yaml:"schema" xml:"schema"`
Type string `json:"type" yaml:"type" xml:"type"`
Length int `json:"length,omitempty" yaml:"length,omitempty" xml:"length,omitempty"`
Precision int `json:"precision,omitempty" yaml:"precision,omitempty" xml:"precision,omitempty"`
Scale int `json:"scale,omitempty" yaml:"scale,omitempty" xml:"scale,omitempty"`
NotNull bool `json:"not_null" yaml:"not_null" xml:"not_null"`
Default interface{} `json:"default,omitempty" yaml:"default,omitempty" xml:"default,omitempty"`
AutoIncrement bool `json:"auto_increment" yaml:"auto_increment" xml:"auto_increment"`
IsPrimaryKey bool `json:"is_primary_key" yaml:"is_primary_key" xml:"is_primary_key"`
Comment string `json:"comment,omitempty" yaml:"comment,omitempty" xml:"comment,omitempty"`
Collation string `json:"collation,omitempty" yaml:"collation,omitempty" xml:"collation,omitempty"`
}
type Index struct {
Name string `json:"name" yaml:"name" xml:"name"`
Table string `json:"table,omitempty" yaml:"table,omitempty" xml:"table,omitempty"`
Schema string `json:"schema,omitempty" yaml:"schema,omitempty" xml:"schema,omitempty"`
Columns []string `json:"columns" yaml:"columns" xml:"columns"`
Unique bool `json:"unique" yaml:"unique" xml:"unique"`
Type string `json:"type" yaml:"type" xml:"type"` // btree, hash, gin, gist, etc.
Where string `json:"where,omitempty" yaml:"where,omitempty" xml:"where,omitempty"` // partial index condition
Concurrent bool `json:"concurrent,omitempty" yaml:"concurrent,omitempty" xml:"concurrent,omitempty"`
Include []string `json:"include,omitempty" yaml:"include,omitempty" xml:"include,omitempty"` // INCLUDE columns
Comment string `json:"comment,omitempty" yaml:"comment,omitempty" xml:"comment,omitempty"`
}
type RelationType string
const (
OneToOne RelationType = "one_to_one"
OneToMany RelationType = "one_to_many"
ManyToMany RelationType = "many_to_many"
)
type Relationship struct {
Name string `json:"name" yaml:"name" xml:"name"`
Type RelationType `json:"type" yaml:"type" xml:"type"`
FromTable string `json:"from_table" yaml:"from_table" xml:"from_table"`
FromSchema string `json:"from_schema" yaml:"from_schema" xml:"from_schema"`
ToTable string `json:"to_table" yaml:"to_table" xml:"to_table"`
ToSchema string `json:"to_schema" yaml:"to_schema" xml:"to_schema"`
ForeignKey string `json:"foreign_key" yaml:"foreign_key" xml:"foreign_key"`
Properties map[string]string `json:"properties" yaml:"properties" xml:"-"`
ThroughTable string `json:"through_table,omitempty" yaml:"through_table,omitempty" xml:"through_table,omitempty"` // For many-to-many
ThroughSchema string `json:"through_schema,omitempty" yaml:"through_schema,omitempty" xml:"through_schema,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty" xml:"description,omitempty"`
}
type Constraint struct {
Name string `json:"name" yaml:"name" xml:"name"`
Type ConstraintType `json:"type" yaml:"type" xml:"type"`
Columns []string `json:"columns" yaml:"columns" xml:"columns"`
Expression string `json:"expression,omitempty" yaml:"expression,omitempty" xml:"expression,omitempty"`
Schema string `json:"schema,omitempty" yaml:"schema,omitempty" xml:"schema,omitempty"`
Table string `json:"table,omitempty" yaml:"table,omitempty" xml:"table,omitempty"`
ReferencedTable string `json:"referenced_table" yaml:"referenced_table" xml:"referenced_table"`
ReferencedSchema string `json:"referenced_schema" yaml:"referenced_schema" xml:"referenced_schema"`
ReferencedColumns []string `json:"referenced_columns" yaml:"referenced_columns" xml:"referenced_columns"`
OnDelete string `json:"on_delete" yaml:"on_delete" xml:"on_delete"` // CASCADE, SET NULL, RESTRICT, etc.
OnUpdate string `json:"on_update" yaml:"on_update" xml:"on_update"`
Deferrable bool `json:"deferrable,omitempty" yaml:"deferrable,omitempty" xml:"deferrable,omitempty"`
InitiallyDeferred bool `json:"initially_deferred,omitempty" yaml:"initially_deferred,omitempty" xml:"initially_deferred,omitempty"`
}
type ConstraintType string
const (
PrimaryKeyConstraint ConstraintType = "primary_key"
ForeignKeyConstraint ConstraintType = "foreign_Key"
UniqueConstraint ConstraintType = "unique"
CheckConstraint ConstraintType = "check"
NotNullConstraint ConstraintType = "not_null"
)
type Script struct {
Name string `json:"name" yaml:"name" xml:"name"`
Description string `json:"description" yaml:"description" xml:"description"`
SQL string `json:"sql" yaml:"sql" xml:"sql"`
Rollback string `json:"rollback,omitempty" yaml:"rollback,omitempty" xml:"rollback,omitempty"`
RunAfter []string `json:"run_after,omitempty" yaml:"run_after,omitempty" xml:"run_after,omitempty"`
Schema string `json:"schema,omitempty" yaml:"schema,omitempty" xml:"schema,omitempty"`
Version string `json:"version,omitempty" yaml:"version,omitempty" xml:"version,omitempty"`
Priority int `json:"priority,omitempty" yaml:"priority,omitempty" xml:"priority,omitempty"`
}

24
pkg/readers/reader.go Normal file
View File

@@ -0,0 +1,24 @@
package readers
import (
"git.warky.dev/wdevs/relspecgo/pkg/models"
)
// Reader defines the interface for reading database specifications
// from various input formats
type Reader interface {
// Read reads and parses the input, returning a Database model
Read() (*models.Database, error)
}
// ReaderOptions contains common options for readers
type ReaderOptions struct {
// FilePath is the path to the input file (if applicable)
FilePath string
// ConnectionString is the database connection string (for DB readers)
ConnectionString string
// Additional options can be added here as needed
Metadata map[string]interface{}
}

View File

@@ -0,0 +1,32 @@
package transform
import (
"git.warky.dev/wdevs/relspecgo/pkg/models"
)
// Transformer provides utilities for transforming database models
type Transformer struct{}
// NewTransformer creates a new Transformer instance
func NewTransformer() *Transformer {
return &Transformer{}
}
// Validate validates a database model for correctness
func (t *Transformer) Validate(db *models.Database) error {
// TODO: Implement validation logic
// - Check for duplicate table names
// - Validate column types
// - Ensure foreign keys reference existing tables/columns
// - Validate relation integrity
return nil
}
// Normalize normalizes a database model to a standard format
func (t *Transformer) Normalize(db *models.Database) (*models.Database, error) {
// TODO: Implement normalization logic
// - Standardize naming conventions
// - Order tables/columns consistently
// - Apply default values
return db, nil
}

24
pkg/writers/writer.go Normal file
View File

@@ -0,0 +1,24 @@
package writers
import (
"git.warky.dev/wdevs/relspecgo/pkg/models"
)
// Writer defines the interface for writing database specifications
// to various output formats
type Writer interface {
// Write takes a Database model and writes it to the desired format
Write(db *models.Database) error
}
// WriterOptions contains common options for writers
type WriterOptions struct {
// OutputPath is the path where the output should be written
OutputPath string
// PackageName is the Go package name (for code generation)
PackageName string
// Additional options can be added here as needed
Metadata map[string]interface{}
}