Merge pull request 'Add StoneSQL migration engine with tests and README updates' (#1) from feature/migrator-implementation into develop
Reviewed-on: #1 Reviewed-by: Cloud Administrator <cloud-admin@noreply.gitstormr.dev>
This commit is contained in:
commit
561dfbc827
50
.gitea/workflows/ci-basic.yml
Normal file
50
.gitea/workflows/ci-basic.yml
Normal file
@ -0,0 +1,50 @@
|
||||
name: Go CI/CD
|
||||
run-name: ${{ github.actor }} is running CI/CD basic
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- main
|
||||
- release/**
|
||||
- develop
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- main
|
||||
- release/**
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
go-ci:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.24'
|
||||
|
||||
- name: Download dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
go mod tidy -x
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
go test -json > test-report.out
|
||||
go test -coverprofile=coverage.out
|
||||
|
||||
- name: SonarQube Analysis
|
||||
uses: SonarSource/sonarqube-scan-action@v5
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
|
||||
|
||||
- name: Build binary
|
||||
shell: bash
|
||||
run: |
|
||||
go build ./...
|
50
.gitea/workflows/ci-protected.yml
Normal file
50
.gitea/workflows/ci-protected.yml
Normal file
@ -0,0 +1,50 @@
|
||||
name: Go CI/CD
|
||||
run-name: ${{ github.actor }} is running CI/CD protected
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/**
|
||||
- develop
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- release/**
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
go-ci:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.24'
|
||||
|
||||
- name: Download dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
go mod tidy -x
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
go test -json > test-report.out
|
||||
go test -coverprofile=coverage.out
|
||||
|
||||
- name: SonarQube Analysis
|
||||
uses: SonarSource/sonarqube-scan-action@v5
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
|
||||
|
||||
- name: Build binary
|
||||
shell: bash
|
||||
run: |
|
||||
go build ./...
|
43
.gitea/workflows/ci-tag.yml
Normal file
43
.gitea/workflows/ci-tag.yml
Normal file
@ -0,0 +1,43 @@
|
||||
name: Go CI/CD
|
||||
run-name: ${{ github.actor }} is running CI/CD Tag
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
go-ci:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.24'
|
||||
|
||||
- name: Download dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
go mod tidy -x
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
go test -json > test-report.out
|
||||
go test -coverprofile=coverage.out
|
||||
|
||||
- name: SonarQube Analysis
|
||||
uses: SonarSource/sonarqube-scan-action@v5
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
|
||||
|
||||
- name: Build binary
|
||||
shell: bash
|
||||
run: |
|
||||
go build ./...
|
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
4
.idea/misc.xml
generated
Normal file
4
.idea/misc.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GOROOT" url="file:///usr/local/go" />
|
||||
</project>
|
4
.idea/vcs.xml
generated
Normal file
4
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings" defaultProject="true" />
|
||||
</project>
|
83
README.md
83
README.md
@ -1,3 +1,82 @@
|
||||
# stonesql
|
||||
# StoneSQL - **10 BILLION% MIGRATION PRECISION!**
|
||||
|
||||
StoneSQL - Ultimate SQL Migration Engine! ⚡ Scientific database versioning with atomic precision. Embedded migration files, error tracking & stone-utils integration. 10 billion% more reliable schema changes! 🚀
|
||||
Ultimate SQL Migration Engine! ⚡ Scientific database versioning with atomic precision. Embedded migration files, error tracking & stone-utils integration. 10 billion% more reliable schema changes! 🚀
|
||||
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
|
||||
## 🚀 Why StoneSQL?
|
||||
|
||||
- **Embedded SQL migrations** with atomic precision
|
||||
- **Scientifically versioned** schema changes
|
||||
- **100% reproducible** database states
|
||||
- **10 billion schema changes/sec** (theoretical)
|
||||
|
||||
## 💥 Installation
|
||||
|
||||
```bash
|
||||
go get gitstormr.dev/stone-utils/stonesql@latest
|
||||
```
|
||||
|
||||
## ⚡ Basic Usage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"gitstormr.dev/stone-utils/stonesql"
|
||||
)
|
||||
|
||||
//go:embed migrations/*.sql
|
||||
var migrations embed.FS
|
||||
|
||||
type DBMigrator struct{}
|
||||
|
||||
func (m *DBMigrator) ExecuteMigration(ctx context.Context, name, sql string) error {
|
||||
// Execute with your favorite database driver
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := stonesql.RunMigrations(context.Background(), &DBMigrator{}, migrations, "migrations"); err != nil {
|
||||
panic(err) // Handle error properly in production!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔬 Core Features
|
||||
|
||||
### Embedded migration files
|
||||
|
||||
```text
|
||||
migrations/
|
||||
├─ 001_init.sql
|
||||
├─ 002_add_users.sql
|
||||
└─ 003_add_indexes.sql
|
||||
```
|
||||
|
||||
### Scientific error tracking
|
||||
|
||||
```go
|
||||
ErrWalkDirFailed = stoneerror.New(2001, "failed walking migrations")
|
||||
ErrReadMigrationFailed = stoneerror.New(2002, "failed reading SQL file")
|
||||
// ...and more!
|
||||
```
|
||||
|
||||
## ⚗️ Scientific Benchmarks
|
||||
|
||||
| METRIC | STANDARD LIB | STONESQL |
|
||||
|-----------------|---------------|----------|
|
||||
| Reliability | 80% | 10B% |
|
||||
| Reproducibility | ❌ | ✅✅✅ |
|
||||
| Atomicity | Maybe | ALWAYS |
|
||||
|
||||
**Join the Scientific Revolution!**
|
||||
|
||||
> "This isn't just schema management - it's revolutionizing database evolution like we revived civilization!" - Senku Ishigami
|
||||
|
||||
Kingdom of Science Approved
|
||||
|
||||
(Now with 100% more Chrome screaming "SO BADASS!")
|
5
go.mod
Normal file
5
go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module gitstormr.dev/stone-utils/stonesql
|
||||
|
||||
go 1.24
|
||||
|
||||
require gitstormr.dev/stone-utils/stoneerror v1.0.0
|
2
go.sum
Normal file
2
go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
gitstormr.dev/stone-utils/stoneerror v1.0.0 h1:EJpn4MZBeYifWlCoQBEGmGdEtNABjOrUzJmQSqcXqY0=
|
||||
gitstormr.dev/stone-utils/stoneerror v1.0.0/go.mod h1:Rs34Oz14ILsbkZ++Ov9PObTz7mRvyyvcCcML9AeyIyk=
|
106
migrator.go
Normal file
106
migrator.go
Normal file
@ -0,0 +1,106 @@
|
||||
package stonesql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
|
||||
"gitstormr.dev/stone-utils/stoneerror"
|
||||
)
|
||||
|
||||
// SQLFileExtension represents the file extension for SQL migration files.
|
||||
const (
|
||||
SQLFileExtension = ".sql"
|
||||
)
|
||||
|
||||
// ErrWalkDirFailed represents an error for failed directory traversal.
|
||||
// ErrReadMigrationFailed represents an error for reading migration files.
|
||||
// ErrExecuteMigrationFailed represents an error during migration execution.
|
||||
// ErrMigrationProcessFailed represents a general migration process failure.
|
||||
var (
|
||||
ErrWalkDirFailed = stoneerror.New(
|
||||
2001,
|
||||
"failed to walk migration directory",
|
||||
)
|
||||
ErrReadMigrationFailed = stoneerror.New(
|
||||
2002,
|
||||
"failed to read migration file",
|
||||
)
|
||||
ErrExecuteMigrationFailed = stoneerror.New(
|
||||
2003,
|
||||
"failed to execute migration",
|
||||
)
|
||||
ErrMigrationProcessFailed = stoneerror.New(
|
||||
2004,
|
||||
"migration process failed",
|
||||
)
|
||||
)
|
||||
|
||||
// Migrator defines the interface for executing SQL migrations.
|
||||
// ExecuteMigration runs a migration given its name and SQL content.
|
||||
type Migrator interface {
|
||||
ExecuteMigration(ctx context.Context, name string, sqlContent string) error
|
||||
}
|
||||
|
||||
// RunMigrations performs a series of database migrations from embedded files.
|
||||
// It traverses the provided filesystem path, reads SQL files, and executes them.
|
||||
// If an error occurs during traversal, reading, or execution, it wraps and returns it.
|
||||
// Context to be used for execution is passed via the ctx parameter.
|
||||
// The migrator parameter executes individual SQL content for migrations.
|
||||
// The migrationsFS parameter provides an embedded filesystem for the SQL files.
|
||||
// The path parameter specifies the directory within the embedded FS to search in.
|
||||
// Returns an error if any step in the migration process fails.
|
||||
func RunMigrations(
|
||||
ctx context.Context,
|
||||
migrator Migrator,
|
||||
migrationsFS embed.FS,
|
||||
path string,
|
||||
) error {
|
||||
walkErr := fs.WalkDir(
|
||||
migrationsFS,
|
||||
path,
|
||||
func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return stoneerror.Wrap(
|
||||
err, ErrWalkDirFailed.Code,
|
||||
ErrWalkDirFailed.Message,
|
||||
).
|
||||
WithMetadata("path", path)
|
||||
}
|
||||
|
||||
if !d.IsDir() && filepath.Ext(path) == SQLFileExtension {
|
||||
sqlContent, readErr := migrationsFS.ReadFile(path)
|
||||
if readErr != nil {
|
||||
return stoneerror.Wrap(
|
||||
readErr, ErrReadMigrationFailed.Code,
|
||||
ErrReadMigrationFailed.Message,
|
||||
).
|
||||
WithMetadata("file", path)
|
||||
}
|
||||
|
||||
if err = migrator.ExecuteMigration(
|
||||
ctx, path, string(sqlContent),
|
||||
); err != nil {
|
||||
return stoneerror.Wrap(
|
||||
err, ErrExecuteMigrationFailed.Code,
|
||||
ErrExecuteMigrationFailed.Message,
|
||||
).
|
||||
WithMetadata("migration", path)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if walkErr != nil {
|
||||
return stoneerror.Wrap(
|
||||
walkErr, ErrMigrationProcessFailed.Code,
|
||||
ErrMigrationProcessFailed.Message,
|
||||
).
|
||||
WithMetadata("rootPath", path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
43
migrator_test.go
Normal file
43
migrator_test.go
Normal file
@ -0,0 +1,43 @@
|
||||
package stonesql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gitstormr.dev/stone-utils/stonesql/test"
|
||||
)
|
||||
|
||||
type migratorSuccessMock struct{}
|
||||
|
||||
func (m *migratorSuccessMock) ExecuteMigration(
|
||||
ctx context.Context, name string, sqlContent string,
|
||||
) error {
|
||||
fmt.Println(name, sqlContent)
|
||||
return nil
|
||||
}
|
||||
|
||||
type migratorFailureMock struct{}
|
||||
|
||||
func (m *migratorFailureMock) ExecuteMigration(
|
||||
ctx context.Context, name string, sqlContent string,
|
||||
) error {
|
||||
return fmt.Errorf("failed to execute migration %s", name)
|
||||
}
|
||||
|
||||
func Test_MigrationSuccess(t *testing.T) {
|
||||
migrator := &migratorSuccessMock{}
|
||||
err := RunMigrations(context.Background(), migrator, test.TestFS, ".")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_MigrationFailure(t *testing.T) {
|
||||
migrator := &migratorFailureMock{}
|
||||
err := RunMigrations(context.Background(), migrator, test.TestFS, ".")
|
||||
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
}
|
10
sonar-project.properties
Normal file
10
sonar-project.properties
Normal file
@ -0,0 +1,10 @@
|
||||
sonar.projectKey=9abe63b7-edeb-482a-ac71-9f4afb2947b1
|
||||
sonar.projectName=stone-utils/stonesql
|
||||
sonar.language=go
|
||||
sonar.sources=.
|
||||
sonar.exclusions=**/*_test.go, test/**
|
||||
sonar.tests=.
|
||||
sonar.test.inclusions=**/*_test.go
|
||||
sonar.go.tests.reportPaths=test-report.out
|
||||
sonar.go.coverage.reportPaths=coverage.out
|
||||
sonar.qualitygate.wait=true
|
8
test/embed.go
Normal file
8
test/embed.go
Normal file
@ -0,0 +1,8 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"embed"
|
||||
)
|
||||
|
||||
//go:embed *.sql
|
||||
var TestFS embed.FS
|
1
test/test.sql
Normal file
1
test/test.sql
Normal file
@ -0,0 +1 @@
|
||||
SELECT 1 == 1;
|
Loading…
x
Reference in New Issue
Block a user