chore(ci): add govulncheck, staticcheck, go vet, gofumpt gates
* Add lint/format checks to the Gitea release workflow and Makefile (targets: vet, fmt, fmt-check, staticcheck, govulncheck, check) * Switch .golangci.json formatter from gofmt to gofumpt (extra.group-params) * Bump golang.org/x/text 0.37.0 -> 0.39.0 for GO-2026-5970; re-vendor * Fix staticcheck S1011 in pkg/diff; drop unused pgsql writer helpers * Fix gocritic unnamedResult (pkg/diff) and rangeValCopy (pkg/pgsql) * Apply gofumpt + goimports formatting across the tree
This commit is contained in:
@@ -137,7 +137,10 @@ func TestScanDir_OrdersByPriorityThenSequence(t *testing.T) {
|
||||
t.Fatalf("expected 4 items, got %d", len(items))
|
||||
}
|
||||
|
||||
type ps struct{ p int; s uint }
|
||||
type ps struct {
|
||||
p int
|
||||
s uint
|
||||
}
|
||||
want := []ps{{1, 1}, {1, 2}, {2, 1}, {2, 2}}
|
||||
for i, w := range want {
|
||||
got := ps{items[i].Priority, items[i].Sequence}
|
||||
|
||||
+3
-5
@@ -264,7 +264,7 @@ func compareColumnDetails(source, target *models.Column) map[string]any {
|
||||
|
||||
// comparableColumn accepts DBML's compact type/default spelling as well as
|
||||
// PostgreSQL's normalized fields (for example varchar(255) vs varchar + 255).
|
||||
func comparableColumn(column *models.Column) (string, int, any) {
|
||||
func comparableColumn(column *models.Column) (normalizedType string, length int, defaultVal any) {
|
||||
typeName := strings.TrimSpace(column.Type)
|
||||
defaultValue := column.Default
|
||||
lower := strings.ToLower(typeName)
|
||||
@@ -274,7 +274,7 @@ func comparableColumn(column *models.Column) (string, int, any) {
|
||||
}
|
||||
typeName = strings.TrimSpace(typeName[:i])
|
||||
}
|
||||
length := column.Length
|
||||
length = column.Length
|
||||
if open := strings.LastIndex(typeName, "("); open >= 0 && strings.HasSuffix(typeName, ")") {
|
||||
if parsed, err := strconv.Atoi(strings.TrimSpace(typeName[open+1 : len(typeName)-1])); err == nil && length == 0 {
|
||||
length = parsed
|
||||
@@ -353,9 +353,7 @@ func compareIndexes(source, target map[string]*models.Index) *IndexDiff {
|
||||
}
|
||||
|
||||
for _, key := range sortedKeys(remainingTarget) {
|
||||
for _, index := range remainingTarget[key] {
|
||||
diff.Extra = append(diff.Extra, index)
|
||||
}
|
||||
diff.Extra = append(diff.Extra, remainingTarget[key]...)
|
||||
}
|
||||
return diff
|
||||
}
|
||||
|
||||
@@ -130,7 +130,6 @@ func TestFormatSummary(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
err := formatSummary(tt.result, &buf)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("formatSummary() error = %v", err)
|
||||
return
|
||||
@@ -159,7 +158,6 @@ func TestFormatJSON(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := formatJSON(result, &buf)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("formatJSON() error = %v", err)
|
||||
return
|
||||
@@ -288,7 +286,6 @@ func TestFormatHTML(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
err := formatHTML(tt.result, &buf)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("formatHTML() error = %v", err)
|
||||
return
|
||||
@@ -334,7 +331,6 @@ func TestFormatSummaryWithColumns(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := formatSummary(result, &buf)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("formatSummary() error = %v", err)
|
||||
return
|
||||
@@ -383,7 +379,6 @@ func TestFormatSummaryWithIndexes(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := formatSummary(result, &buf)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("formatSummary() error = %v", err)
|
||||
return
|
||||
@@ -425,7 +420,6 @@ func TestFormatSummaryWithConstraints(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := formatSummary(result, &buf)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("formatSummary() error = %v", err)
|
||||
return
|
||||
@@ -448,7 +442,6 @@ func TestFormatJSONIndentation(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := formatJSON(result, &buf)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("formatJSON() error = %v", err)
|
||||
return
|
||||
|
||||
@@ -168,7 +168,7 @@ func getValidator(functionName string) (validatorFunc, bool) {
|
||||
}
|
||||
|
||||
// createResult is a helper to create a validation result
|
||||
func createResult(ruleName string, passed bool, message string, location string, context map[string]interface{}) ValidationResult {
|
||||
func createResult(ruleName string, passed bool, message, location string, context map[string]interface{}) ValidationResult {
|
||||
return ValidationResult{
|
||||
RuleName: ruleName,
|
||||
Message: message,
|
||||
|
||||
@@ -29,7 +29,6 @@ func TestInspect(t *testing.T) {
|
||||
|
||||
inspector := NewInspector(db, config)
|
||||
report, err := inspector.Inspect()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Inspect() returned error: %v", err)
|
||||
}
|
||||
@@ -103,7 +102,6 @@ func TestInspectWithDisabledRules(t *testing.T) {
|
||||
|
||||
inspector := NewInspector(db, config)
|
||||
report, err := inspector.Inspect()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Inspect() with disabled rules returned error: %v", err)
|
||||
}
|
||||
@@ -135,7 +133,6 @@ func TestInspectWithEnforcedRules(t *testing.T) {
|
||||
|
||||
inspector := NewInspector(db, config)
|
||||
report, err := inspector.Inspect()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Inspect() returned error: %v", err)
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ func (f *MarkdownFormatter) formatHeader(text string) string {
|
||||
return f.formatBold("# " + text)
|
||||
}
|
||||
|
||||
func (f *MarkdownFormatter) formatSubheader(text string, color string) string {
|
||||
func (f *MarkdownFormatter) formatSubheader(text, color string) string {
|
||||
header := "### " + text
|
||||
if f.UseColors {
|
||||
return color + colorBold + header + colorReset
|
||||
@@ -156,7 +156,7 @@ func (f *MarkdownFormatter) formatBold(text string) string {
|
||||
return "**" + text + "**"
|
||||
}
|
||||
|
||||
func (f *MarkdownFormatter) colorize(text string, color string) string {
|
||||
func (f *MarkdownFormatter) colorize(text, color string) string {
|
||||
if f.UseColors {
|
||||
return color + text + colorReset
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ func TestGetDefaultConfig(t *testing.T) {
|
||||
func TestLoadConfig_NonExistentFile(t *testing.T) {
|
||||
// Try to load a non-existent file
|
||||
config, err := LoadConfig("/path/to/nonexistent/file.yaml")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("LoadConfig() with non-existent file returned error: %v", err)
|
||||
}
|
||||
@@ -83,7 +82,7 @@ rules:
|
||||
message: "Table name too long"
|
||||
`
|
||||
|
||||
err := os.WriteFile(configPath, []byte(configContent), 0644)
|
||||
err := os.WriteFile(configPath, []byte(configContent), 0o644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test config file: %v", err)
|
||||
}
|
||||
@@ -133,7 +132,7 @@ func TestLoadConfig_InvalidYAML(t *testing.T) {
|
||||
|
||||
invalidContent := `invalid: yaml: content: {[}]`
|
||||
|
||||
err := os.WriteFile(configPath, []byte(invalidContent), 0644)
|
||||
err := os.WriteFile(configPath, []byte(invalidContent), 0o644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test config file: %v", err)
|
||||
}
|
||||
|
||||
+9
-9
@@ -118,7 +118,7 @@ func (r *MergeResult) mergeSchemaContents(target, source *models.Schema, opts *M
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MergeResult) mergeTables(schema *models.Schema, source *models.Schema, opts *MergeOptions) {
|
||||
func (r *MergeResult) mergeTables(schema, source *models.Schema, opts *MergeOptions) {
|
||||
// Create map of existing tables
|
||||
existingTables := make(map[string]*models.Table)
|
||||
for _, table := range schema.Tables {
|
||||
@@ -150,7 +150,7 @@ func (r *MergeResult) mergeTables(schema *models.Schema, source *models.Schema,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MergeResult) mergeColumns(table *models.Table, srcTable *models.Table) {
|
||||
func (r *MergeResult) mergeColumns(table, srcTable *models.Table) {
|
||||
// Create map of existing columns
|
||||
existingColumns := make(map[string]*models.Column)
|
||||
for colName := range table.Columns {
|
||||
@@ -185,7 +185,7 @@ func (r *MergeResult) mergeColumns(table *models.Table, srcTable *models.Table)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MergeResult) mergeConstraints(table *models.Table, srcTable *models.Table) {
|
||||
func (r *MergeResult) mergeConstraints(table, srcTable *models.Table) {
|
||||
// Initialize constraints map if nil
|
||||
if table.Constraints == nil {
|
||||
table.Constraints = make(map[string]*models.Constraint)
|
||||
@@ -208,7 +208,7 @@ func (r *MergeResult) mergeConstraints(table *models.Table, srcTable *models.Tab
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MergeResult) mergeIndexes(table *models.Table, srcTable *models.Table) {
|
||||
func (r *MergeResult) mergeIndexes(table, srcTable *models.Table) {
|
||||
// Initialize indexes map if nil
|
||||
if table.Indexes == nil {
|
||||
table.Indexes = make(map[string]*models.Index)
|
||||
@@ -231,7 +231,7 @@ func (r *MergeResult) mergeIndexes(table *models.Table, srcTable *models.Table)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MergeResult) mergeViews(schema *models.Schema, source *models.Schema) {
|
||||
func (r *MergeResult) mergeViews(schema, source *models.Schema) {
|
||||
// Create map of existing views
|
||||
existingViews := make(map[string]*models.View)
|
||||
for _, view := range schema.Views {
|
||||
@@ -250,7 +250,7 @@ func (r *MergeResult) mergeViews(schema *models.Schema, source *models.Schema) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MergeResult) mergeSequences(schema *models.Schema, source *models.Schema) {
|
||||
func (r *MergeResult) mergeSequences(schema, source *models.Schema) {
|
||||
// Create map of existing sequences
|
||||
existingSequences := make(map[string]*models.Sequence)
|
||||
for _, seq := range schema.Sequences {
|
||||
@@ -269,7 +269,7 @@ func (r *MergeResult) mergeSequences(schema *models.Schema, source *models.Schem
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MergeResult) mergeEnums(schema *models.Schema, source *models.Schema) {
|
||||
func (r *MergeResult) mergeEnums(schema, source *models.Schema) {
|
||||
// Create map of existing enums
|
||||
existingEnums := make(map[string]*models.Enum)
|
||||
for _, enum := range schema.Enums {
|
||||
@@ -288,7 +288,7 @@ func (r *MergeResult) mergeEnums(schema *models.Schema, source *models.Schema) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MergeResult) mergeRelations(schema *models.Schema, source *models.Schema) {
|
||||
func (r *MergeResult) mergeRelations(schema, source *models.Schema) {
|
||||
// Create map of existing relations
|
||||
existingRelations := make(map[string]*models.Relationship)
|
||||
for _, rel := range schema.Relations {
|
||||
@@ -306,7 +306,7 @@ func (r *MergeResult) mergeRelations(schema *models.Schema, source *models.Schem
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MergeResult) mergeDomains(target *models.Database, source *models.Database) {
|
||||
func (r *MergeResult) mergeDomains(target, source *models.Database) {
|
||||
// Create map of existing domains
|
||||
existingDomains := make(map[string]*models.Domain)
|
||||
for _, domain := range target.Domains {
|
||||
|
||||
@@ -247,7 +247,8 @@ var extensionFunctionPrefixes = buildExtensionIndex(func(ext Extension) []string
|
||||
|
||||
func buildExtensionIndex(keys func(Extension) []string) map[string]string {
|
||||
index := make(map[string]string)
|
||||
for _, ext := range postgresExtensions {
|
||||
for name := range postgresExtensions {
|
||||
ext := postgresExtensions[name]
|
||||
for _, key := range keys(ext) {
|
||||
// Deterministic on collision: the alphabetically first extension wins.
|
||||
if existing, ok := index[key]; ok && existing < ext.Name {
|
||||
|
||||
@@ -245,7 +245,7 @@ func (r *Reader) getReceiverType(expr ast.Expr) string {
|
||||
}
|
||||
|
||||
// parseTableNameMethod parses a TableName() method and extracts the table and schema name
|
||||
func (r *Reader) parseTableNameMethod(funcDecl *ast.FuncDecl) (tableName string, schemaName string) {
|
||||
func (r *Reader) parseTableNameMethod(funcDecl *ast.FuncDecl) (tableName, schemaName string) {
|
||||
if funcDecl.Body == nil {
|
||||
return "", ""
|
||||
}
|
||||
@@ -578,7 +578,7 @@ func (r *Reader) parseIndexesFromTag(table *models.Table, column *models.Column,
|
||||
}
|
||||
|
||||
// extractTableNameFromTag extracts table and schema from bun tag
|
||||
func (r *Reader) extractTableNameFromTag(tag string) (tableName string, schemaName string) {
|
||||
func (r *Reader) extractTableNameFromTag(tag string) (tableName, schemaName string) {
|
||||
// Extract bun tag value
|
||||
re := regexp.MustCompile(`bun:"table:([^"]+)"`)
|
||||
matches := re.FindStringSubmatch(tag)
|
||||
@@ -712,12 +712,12 @@ func (r *Reader) parseTypeWithLength(typeStr string) (baseType string, length in
|
||||
if pgsql.SupportsLength(rawBaseType) {
|
||||
if _, err := fmt.Sscanf(matches[2], "%d", &length); err == nil {
|
||||
baseType = pgsql.CanonicalizeBaseType(rawBaseType)
|
||||
return
|
||||
return baseType, length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
return baseType, length
|
||||
}
|
||||
|
||||
// goTypeToSQL maps Go types to SQL types
|
||||
|
||||
@@ -701,7 +701,7 @@ func (r *Reader) parseColumn(line, tableName, schemaName string) (*models.Column
|
||||
return column, constraint
|
||||
}
|
||||
|
||||
func splitInlineComment(line string) (content string, inlineComment string) {
|
||||
func splitInlineComment(line string) (content, inlineComment string) {
|
||||
commentStart := strings.Index(line, "//")
|
||||
if commentStart == -1 {
|
||||
return line, ""
|
||||
@@ -710,7 +710,7 @@ func splitInlineComment(line string) (content string, inlineComment string) {
|
||||
return strings.TrimSpace(line[:commentStart]), strings.TrimSpace(line[commentStart+2:])
|
||||
}
|
||||
|
||||
func splitColumnSignatureAndAttrs(line string) (signature string, attrs string) {
|
||||
func splitColumnSignatureAndAttrs(line string) (signature, attrs string) {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if trimmed == "" || !strings.HasSuffix(trimmed, "]") {
|
||||
return trimmed, ""
|
||||
@@ -736,7 +736,7 @@ func splitColumnSignatureAndAttrs(line string) (signature string, attrs string)
|
||||
return trimmed, ""
|
||||
}
|
||||
|
||||
func parseColumnSignature(signature string) (columnName string, columnType string, ok bool) {
|
||||
func parseColumnSignature(signature string) (columnName, columnType string, ok bool) {
|
||||
signature = strings.TrimSpace(signature)
|
||||
if signature == "" {
|
||||
return "", "", false
|
||||
@@ -1041,5 +1041,5 @@ func (r *Reader) parseTableRef(ref string) (schema, table string, columns []stri
|
||||
table = stripQuotes(parts[0])
|
||||
}
|
||||
|
||||
return
|
||||
return schema, table, columns
|
||||
}
|
||||
|
||||
@@ -689,7 +689,7 @@ func TestReadDirectory_CommentedRefsLast(t *testing.T) {
|
||||
func TestReadDirectory_EmptyDirectory(t *testing.T) {
|
||||
// Create a temporary empty directory
|
||||
tmpDir := filepath.Join("..", "..", "..", "tests", "assets", "dbml", "empty_test_dir")
|
||||
err := os.MkdirAll(tmpDir, 0755)
|
||||
err := os.MkdirAll(tmpDir, 0o755)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp directory: %v", err)
|
||||
}
|
||||
@@ -956,7 +956,7 @@ func TestReader_CompositePKIndex(t *testing.T) {
|
||||
`
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "composite_pk.dbml")
|
||||
if err := os.WriteFile(path, []byte(dbmlContent), 0644); err != nil {
|
||||
if err := os.WriteFile(path, []byte(dbmlContent), 0o644); err != nil {
|
||||
t.Fatalf("failed to write fixture: %v", err)
|
||||
}
|
||||
|
||||
@@ -1005,7 +1005,7 @@ func TestReader_ColumnPKOrderPreserved(t *testing.T) {
|
||||
`
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "column_pk_order.dbml")
|
||||
if err := os.WriteFile(path, []byte(dbmlContent), 0644); err != nil {
|
||||
if err := os.WriteFile(path, []byte(dbmlContent), 0o644); err != nil {
|
||||
t.Fatalf("failed to write fixture: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -246,7 +246,7 @@ func (r *Reader) getReceiverType(expr ast.Expr) string {
|
||||
}
|
||||
|
||||
// parseTableNameMethod parses a TableName() method and extracts the table and schema name
|
||||
func (r *Reader) parseTableNameMethod(funcDecl *ast.FuncDecl) (tableName string, schemaName string) {
|
||||
func (r *Reader) parseTableNameMethod(funcDecl *ast.FuncDecl) (tableName, schemaName string) {
|
||||
if funcDecl.Body == nil {
|
||||
return "", ""
|
||||
}
|
||||
@@ -669,7 +669,7 @@ func (r *Reader) parseIndexesFromTag(table *models.Table, column *models.Column,
|
||||
}
|
||||
|
||||
// extractTableFromGormTag extracts table and schema from gorm tag
|
||||
func (r *Reader) extractTableFromGormTag(tag string) (tablename string, schemaName string) {
|
||||
func (r *Reader) extractTableFromGormTag(tag string) (tablename, schemaName string) {
|
||||
// This is typically set via TableName() method, not in tags
|
||||
// We'll return empty strings and rely on deriveTableName
|
||||
return "", ""
|
||||
@@ -794,12 +794,12 @@ func (r *Reader) parseTypeWithLength(typeStr string) (baseType string, length in
|
||||
if pgsql.SupportsLength(rawBaseType) && !strings.Contains(parens, ",") {
|
||||
if _, err := fmt.Sscanf(parens, "%d", &length); err == nil {
|
||||
baseType = pgsql.CanonicalizeBaseType(rawBaseType)
|
||||
return
|
||||
return baseType, length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
return baseType, length
|
||||
}
|
||||
|
||||
// parseTypeWithReferences parses a type string and extracts base type, length, and references
|
||||
@@ -816,12 +816,12 @@ func (r *Reader) parseTypeWithReferences(typeStr string) (baseType string, lengt
|
||||
|
||||
// Parse base type for length
|
||||
baseType, length = r.parseTypeWithLength(baseTypePart)
|
||||
return
|
||||
return baseType, length, refInfo
|
||||
}
|
||||
|
||||
// No references, just parse type and length
|
||||
baseType, length = r.parseTypeWithLength(typeStr)
|
||||
return
|
||||
return baseType, length, refInfo
|
||||
}
|
||||
|
||||
// parseGormTag parses a gorm tag string into a map
|
||||
|
||||
@@ -32,7 +32,7 @@ func (r *Reader) isScalarType(typeName string, ctx *parseContext) bool {
|
||||
return commonCustomScalars[typeName]
|
||||
}
|
||||
|
||||
func (r *Reader) graphQLTypeToSQL(gqlType string, fieldName string, typeName string) string {
|
||||
func (r *Reader) graphQLTypeToSQL(gqlType, fieldName, typeName string) string {
|
||||
// Check for ID type with configurable mapping
|
||||
if gqlType == "ID" {
|
||||
// Check metadata for ID type preference
|
||||
|
||||
@@ -3,9 +3,10 @@ package mssql
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/mssql"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TestMapDataType tests MSSQL type mapping to canonical types
|
||||
@@ -38,9 +39,9 @@ func TestMapDataType(t *testing.T) {
|
||||
// TestConvertCanonicalToMSSQL tests canonical to MSSQL type conversion
|
||||
func TestConvertCanonicalToMSSQL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
canonicalType string
|
||||
expectedMSSQL string
|
||||
name string
|
||||
canonicalType string
|
||||
expectedMSSQL string
|
||||
}{
|
||||
{"int to INT", "int", "INT"},
|
||||
{"int64 to BIGINT", "int64", "BIGINT"},
|
||||
@@ -63,9 +64,9 @@ func TestConvertCanonicalToMSSQL(t *testing.T) {
|
||||
// TestConvertMSSQLToCanonical tests MSSQL to canonical type conversion
|
||||
func TestConvertMSSQLToCanonical(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mssqlType string
|
||||
expectedType string
|
||||
name string
|
||||
mssqlType string
|
||||
expectedType string
|
||||
}{
|
||||
{"INT to int", "INT", "int"},
|
||||
{"BIGINT to int64", "BIGINT", "int64"},
|
||||
|
||||
@@ -28,7 +28,7 @@ model User {
|
||||
id Int @id @default(autoincrement())
|
||||
}`
|
||||
|
||||
if err := os.WriteFile(schemaPath, []byte(content), 0644); err != nil {
|
||||
if err := os.WriteFile(schemaPath, []byte(content), 0o644); err != nil {
|
||||
t.Fatalf("failed to write schema: %v", err)
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ model User {
|
||||
id Int @id @default(autoincrement())
|
||||
}`
|
||||
|
||||
if err := os.WriteFile(schemaPath, []byte(content), 0644); err != nil {
|
||||
if err := os.WriteFile(schemaPath, []byte(content), 0o644); err != nil {
|
||||
t.Fatalf("failed to write schema: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,6 @@ func (r *Reader) readScripts() ([]*models.Script, error) {
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -30,18 +30,18 @@ func TestReader_ReadDatabase(t *testing.T) {
|
||||
|
||||
for filename, content := range testFiles {
|
||||
filePath := filepath.Join(tempDir, filename)
|
||||
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
|
||||
if err := os.WriteFile(filePath, []byte(content), 0o644); err != nil {
|
||||
t.Fatalf("Failed to create test file %s: %v", filename, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create subdirectory with additional script
|
||||
subDir := filepath.Join(tempDir, "migrations")
|
||||
if err := os.MkdirAll(subDir, 0755); err != nil {
|
||||
if err := os.MkdirAll(subDir, 0o755); err != nil {
|
||||
t.Fatalf("Failed to create subdirectory: %v", err)
|
||||
}
|
||||
subFile := filepath.Join(subDir, "3_001_add_column.sql")
|
||||
if err := os.WriteFile(subFile, []byte("ALTER TABLE users ADD COLUMN email TEXT;"), 0644); err != nil {
|
||||
if err := os.WriteFile(subFile, []byte("ALTER TABLE users ADD COLUMN email TEXT;"), 0o644); err != nil {
|
||||
t.Fatalf("Failed to create subdirectory file: %v", err)
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ func TestReader_ReadSchema(t *testing.T) {
|
||||
|
||||
// Create test SQL file
|
||||
testFile := filepath.Join(tempDir, "1_001_test.sql")
|
||||
if err := os.WriteFile(testFile, []byte("SELECT 1;"), 0644); err != nil {
|
||||
if err := os.WriteFile(testFile, []byte("SELECT 1;"), 0o644); err != nil {
|
||||
t.Fatalf("Failed to create test file: %v", err)
|
||||
}
|
||||
|
||||
@@ -220,14 +220,14 @@ func TestReader_InvalidFilename(t *testing.T) {
|
||||
|
||||
for _, filename := range invalidFiles {
|
||||
filePath := filepath.Join(tempDir, filename)
|
||||
if err := os.WriteFile(filePath, []byte("SELECT 1;"), 0644); err != nil {
|
||||
if err := os.WriteFile(filePath, []byte("SELECT 1;"), 0o644); err != nil {
|
||||
t.Fatalf("Failed to create test file %s: %v", filename, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create one valid file
|
||||
validFile := filepath.Join(tempDir, "1_001_valid.sql")
|
||||
if err := os.WriteFile(validFile, []byte("SELECT 1;"), 0644); err != nil {
|
||||
if err := os.WriteFile(validFile, []byte("SELECT 1;"), 0o644); err != nil {
|
||||
t.Fatalf("Failed to create valid file: %v", err)
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ func TestReader_HyphenFormat(t *testing.T) {
|
||||
|
||||
for filename, content := range testFiles {
|
||||
filePath := filepath.Join(tempDir, filename)
|
||||
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
|
||||
if err := os.WriteFile(filePath, []byte(content), 0o644); err != nil {
|
||||
t.Fatalf("Failed to create test file %s: %v", filename, err)
|
||||
}
|
||||
}
|
||||
@@ -343,7 +343,7 @@ func TestReader_MixedFormat(t *testing.T) {
|
||||
|
||||
for filename, content := range testFiles {
|
||||
filePath := filepath.Join(tempDir, filename)
|
||||
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
|
||||
if err := os.WriteFile(filePath, []byte(content), 0o644); err != nil {
|
||||
t.Fatalf("Failed to create test file %s: %v", filename, err)
|
||||
}
|
||||
}
|
||||
@@ -386,13 +386,13 @@ func TestReader_SkipSymlinks(t *testing.T) {
|
||||
|
||||
// Create a real SQL file
|
||||
realFile := filepath.Join(tempDir, "1_001_real_file.sql")
|
||||
if err := os.WriteFile(realFile, []byte("SELECT 1;"), 0644); err != nil {
|
||||
if err := os.WriteFile(realFile, []byte("SELECT 1;"), 0o644); err != nil {
|
||||
t.Fatalf("Failed to create real file: %v", err)
|
||||
}
|
||||
|
||||
// Create another file to link to
|
||||
targetFile := filepath.Join(tempDir, "2_001_target.sql")
|
||||
if err := os.WriteFile(targetFile, []byte("SELECT 2;"), 0644); err != nil {
|
||||
if err := os.WriteFile(targetFile, []byte("SELECT 2;"), 0o644); err != nil {
|
||||
t.Fatalf("Failed to create target file: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ func mapKeyLess(a, b reflect.Value) bool {
|
||||
|
||||
// MapGet safely gets a value from a map by key
|
||||
// Returns nil if key doesn't exist or not a map
|
||||
func MapGet(m interface{}, key interface{}) interface{} {
|
||||
func MapGet(m, key interface{}) interface{} {
|
||||
v := reflect.ValueOf(m)
|
||||
v, ok := Deref(v)
|
||||
if !ok {
|
||||
|
||||
@@ -111,6 +111,7 @@ func (n *SqlNull[T]) Scan(value any) error {
|
||||
return n.FromString(fmt.Sprintf("%v", value))
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SqlNull[T]) FromString(s string) error {
|
||||
s = strings.TrimSpace(s)
|
||||
n.Valid = false
|
||||
@@ -448,7 +449,7 @@ type (
|
||||
type SqlTimeStamp struct{ SqlNull[time.Time] }
|
||||
|
||||
func (t SqlTimeStamp) MarshalJSON() ([]byte, error) {
|
||||
if !t.Valid || t.Val.IsZero() || t.Val.Before(time.Date(0002, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
if !t.Valid || t.Val.IsZero() || t.Val.Before(time.Date(0o002, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return fmt.Appendf(nil, `"%s"`, t.Val.Format("2006-01-02T15:04:05")), nil
|
||||
@@ -465,14 +466,14 @@ func (t *SqlTimeStamp) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
|
||||
func (t SqlTimeStamp) Value() (driver.Value, error) {
|
||||
if !t.Valid || t.Val.IsZero() || t.Val.Before(time.Date(0002, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
if !t.Valid || t.Val.IsZero() || t.Val.Before(time.Date(0o002, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
return nil, nil
|
||||
}
|
||||
return t.Val.Format("2006-01-02T15:04:05"), nil
|
||||
}
|
||||
|
||||
func (t SqlTimeStamp) MarshalYAML() (any, error) {
|
||||
if !t.Valid || t.Val.IsZero() || t.Val.Before(time.Date(0002, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
if !t.Valid || t.Val.IsZero() || t.Val.Before(time.Date(0o002, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
return nil, nil
|
||||
}
|
||||
return t.Val.Format("2006-01-02T15:04:05"), nil
|
||||
@@ -489,7 +490,7 @@ func (t *SqlTimeStamp) UnmarshalYAML(value *yaml.Node) error {
|
||||
}
|
||||
|
||||
func (t SqlTimeStamp) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||
if !t.Valid || t.Val.IsZero() || t.Val.Before(time.Date(0002, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
if !t.Valid || t.Val.IsZero() || t.Val.Before(time.Date(0o002, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
return e.EncodeElement("", start)
|
||||
}
|
||||
return e.EncodeElement(t.Val.Format("2006-01-02T15:04:05"), start)
|
||||
|
||||
@@ -955,4 +955,3 @@ func TestSqlByteArray_Base64_RoundTrip(t *testing.T) {
|
||||
t.Errorf("Round-trip failed: expected %v, got %v", original, b3.Val)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ func (w *Writer) writeMultiFile(db *models.Database) error {
|
||||
}
|
||||
|
||||
// Create output directory if it doesn't exist
|
||||
if err := os.MkdirAll(w.options.OutputPath, 0755); err != nil {
|
||||
if err := os.MkdirAll(w.options.OutputPath, 0o755); err != nil {
|
||||
return fmt.Errorf("failed to create output directory: %w", err)
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ func (w *Writer) writeMultiFile(db *models.Database) error {
|
||||
filepath := filepath.Join(w.options.OutputPath, filename)
|
||||
|
||||
// Write file
|
||||
if err := os.WriteFile(filepath, []byte(formatted), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath, []byte(formatted), 0o644); err != nil {
|
||||
return fmt.Errorf("failed to write file %s: %w", filename, err)
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@ func (w *Writer) formatCode(code string) (string, error) {
|
||||
// writeOutput writes the content to file or stdout
|
||||
func (w *Writer) writeOutput(content string) error {
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0o644)
|
||||
}
|
||||
|
||||
// Print to stdout
|
||||
|
||||
@@ -27,7 +27,7 @@ func (w *Writer) WriteDatabase(db *models.Database) error {
|
||||
content := w.databaseToDBML(db)
|
||||
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0o644)
|
||||
}
|
||||
|
||||
fmt.Print(content)
|
||||
@@ -39,7 +39,7 @@ func (w *Writer) WriteSchema(schema *models.Schema) error {
|
||||
content := w.schemaToDBML(schema)
|
||||
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0o644)
|
||||
}
|
||||
|
||||
fmt.Print(content)
|
||||
@@ -51,7 +51,7 @@ func (w *Writer) WriteTable(table *models.Table) error {
|
||||
content := w.tableToDBML(table)
|
||||
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0o644)
|
||||
}
|
||||
|
||||
fmt.Print(content)
|
||||
|
||||
@@ -5,9 +5,10 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWriter_WriteTable(t *testing.T) {
|
||||
@@ -152,4 +153,4 @@ func TestWriter_WriteDatabase_OneToOneRelationship(t *testing.T) {
|
||||
output := string(content)
|
||||
|
||||
assert.Contains(t, output, "Ref: public.profiles.user_id - public.users.id")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
||||
dctxreader "git.warky.dev/wdevs/relspecgo/pkg/readers/dctx"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRoundTrip_WriteAndRead(t *testing.T) {
|
||||
|
||||
@@ -5,9 +5,10 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWriter_WriteSchema(t *testing.T) {
|
||||
@@ -149,4 +150,4 @@ func TestWriter_WriteSchema(t *testing.T) {
|
||||
// PrimaryMapping should reference foreign table (posts) fields
|
||||
assert.Len(t, relationResult.PrimaryMappings, 1)
|
||||
assert.NotEmpty(t, relationResult.PrimaryMappings[0].Field)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func (w *Writer) writeJSON(data interface{}) error {
|
||||
}
|
||||
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, jsonData, 0644)
|
||||
return os.WriteFile(w.options.OutputPath, jsonData, 0o644)
|
||||
}
|
||||
|
||||
// If no output path, print to stdout
|
||||
|
||||
@@ -115,7 +115,7 @@ func (w *Writer) writeMultiFile(db *models.Database) error {
|
||||
}
|
||||
|
||||
// Create output directory if it doesn't exist
|
||||
if err := os.MkdirAll(w.options.OutputPath, 0755); err != nil {
|
||||
if err := os.MkdirAll(w.options.OutputPath, 0o755); err != nil {
|
||||
return fmt.Errorf("failed to create output directory: %w", err)
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ func (w *Writer) writeEnumsFile(schema *models.Schema) error {
|
||||
|
||||
// Write to enums.ts file
|
||||
filename := filepath.Join(w.options.OutputPath, "enums.ts")
|
||||
return os.WriteFile(filename, []byte(code), 0644)
|
||||
return os.WriteFile(filename, []byte(code), 0o644)
|
||||
}
|
||||
|
||||
// writeTableFile writes a single table to its own file
|
||||
@@ -200,7 +200,7 @@ func (w *Writer) writeTableFile(table *models.Table, schema *models.Schema, db *
|
||||
// Sanitize table name to remove quotes, comments, and invalid characters
|
||||
safeTableName := writers.SanitizeFilename(table.Name)
|
||||
filename := filepath.Join(w.options.OutputPath, safeTableName+".ts")
|
||||
return os.WriteFile(filename, []byte(code), 0644)
|
||||
return os.WriteFile(filename, []byte(code), 0o644)
|
||||
}
|
||||
|
||||
// buildTableData builds TableData from a models.Table
|
||||
@@ -533,7 +533,7 @@ func (w *Writer) getForeignKeyForColumn(columnName string, table *models.Table)
|
||||
// writeOutput writes the content to file or stdout
|
||||
func (w *Writer) writeOutput(content string) error {
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0o644)
|
||||
}
|
||||
|
||||
// Print to stdout
|
||||
|
||||
@@ -152,7 +152,7 @@ func (w *Writer) writeMultiFile(db *models.Database) error {
|
||||
}
|
||||
|
||||
// Create output directory if it doesn't exist
|
||||
if err := os.MkdirAll(w.options.OutputPath, 0755); err != nil {
|
||||
if err := os.MkdirAll(w.options.OutputPath, 0o755); err != nil {
|
||||
return fmt.Errorf("failed to create output directory: %w", err)
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ func (w *Writer) writeMultiFile(db *models.Database) error {
|
||||
filepath := filepath.Join(w.options.OutputPath, filename)
|
||||
|
||||
// Write file
|
||||
if err := os.WriteFile(filepath, []byte(formatted), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath, []byte(formatted), 0o644); err != nil {
|
||||
return fmt.Errorf("failed to write file %s: %w", filename, err)
|
||||
}
|
||||
|
||||
@@ -422,7 +422,7 @@ func (w *Writer) formatCode(code string) (string, error) {
|
||||
// writeOutput writes the content to file or stdout
|
||||
func (w *Writer) writeOutput(content string) error {
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0o644)
|
||||
}
|
||||
|
||||
// Print to stdout
|
||||
|
||||
@@ -76,7 +76,7 @@ func (w *Writer) generateRelationFields(table *models.Table, db *models.Database
|
||||
return fields
|
||||
}
|
||||
|
||||
func (w *Writer) getManyToManyField(table *models.Table, joinTable *models.Table, db *models.Database) string {
|
||||
func (w *Writer) getManyToManyField(table, joinTable *models.Table, db *models.Database) string {
|
||||
// Find the two FK constraints in the join table
|
||||
var fk1, fk2 *models.Constraint
|
||||
for _, constraint := range joinTable.Constraints {
|
||||
|
||||
@@ -24,7 +24,7 @@ func (w *Writer) WriteDatabase(db *models.Database) error {
|
||||
content := w.databaseToGraphQL(db)
|
||||
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0o644)
|
||||
}
|
||||
|
||||
fmt.Print(content)
|
||||
|
||||
@@ -55,7 +55,7 @@ func (w *Writer) WriteTable(table *models.Table) error {
|
||||
// writeOutput writes the content to file or stdout
|
||||
func (w *Writer) writeOutput(data []byte) error {
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, data, 0644)
|
||||
return os.WriteFile(w.options.OutputPath, data, 0o644)
|
||||
}
|
||||
|
||||
// Print to stdout
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TestGenerateColumnDefinition tests column definition generation
|
||||
|
||||
@@ -47,7 +47,7 @@ func NewMigrationWriter(options *writers.WriterOptions) (*MigrationWriter, error
|
||||
}
|
||||
|
||||
// WriteMigration generates migration scripts using templates
|
||||
func (w *MigrationWriter) WriteMigration(model *models.Database, current *models.Database) error {
|
||||
func (w *MigrationWriter) WriteMigration(model, current *models.Database) error {
|
||||
if model == nil {
|
||||
return fmt.Errorf("model database is required")
|
||||
}
|
||||
@@ -161,7 +161,7 @@ func (w *MigrationWriter) WriteMigration(model *models.Database, current *models
|
||||
}
|
||||
|
||||
// generateSchemaScripts generates migration scripts for a schema using templates
|
||||
func (w *MigrationWriter) generateSchemaScripts(model *models.Schema, current *models.Schema) ([]MigrationScript, error) {
|
||||
func (w *MigrationWriter) generateSchemaScripts(model, current *models.Schema) ([]MigrationScript, error) {
|
||||
scripts := make([]MigrationScript, 0)
|
||||
|
||||
for _, extension := range requiredExtensions(model) {
|
||||
@@ -220,7 +220,7 @@ func (w *MigrationWriter) generateSchemaScripts(model *models.Schema, current *m
|
||||
// generateDropScripts generates DROP scripts using templates.
|
||||
// Returns the scripts and a set of FK constraint keys (schema.table.name) that were
|
||||
// explicitly dropped because their referenced PK was being dropped, so they can be force-recreated.
|
||||
func (w *MigrationWriter) generateDropScripts(model *models.Schema, current *models.Schema) ([]MigrationScript, map[string]bool, error) {
|
||||
func (w *MigrationWriter) generateDropScripts(model, current *models.Schema) ([]MigrationScript, map[string]bool, error) {
|
||||
scripts := make([]MigrationScript, 0)
|
||||
droppedFKs := make(map[string]bool)
|
||||
|
||||
@@ -349,7 +349,7 @@ func (w *MigrationWriter) generateDropScripts(model *models.Schema, current *mod
|
||||
}
|
||||
|
||||
// generateTableScripts generates CREATE/ALTER TABLE scripts using templates
|
||||
func (w *MigrationWriter) generateTableScripts(model *models.Schema, current *models.Schema) ([]MigrationScript, error) {
|
||||
func (w *MigrationWriter) generateTableScripts(model, current *models.Schema) ([]MigrationScript, error) {
|
||||
scripts := make([]MigrationScript, 0)
|
||||
|
||||
// Build map of current tables
|
||||
@@ -394,7 +394,7 @@ func (w *MigrationWriter) generateTableScripts(model *models.Schema, current *mo
|
||||
}
|
||||
|
||||
// generateAlterTableScripts generates ALTER TABLE scripts using templates
|
||||
func (w *MigrationWriter) generateAlterTableScripts(schema *models.Schema, modelTable *models.Table, currentTable *models.Table) ([]MigrationScript, error) {
|
||||
func (w *MigrationWriter) generateAlterTableScripts(schema *models.Schema, modelTable, currentTable *models.Table) ([]MigrationScript, error) {
|
||||
scripts := make([]MigrationScript, 0)
|
||||
|
||||
// Build map of current columns
|
||||
@@ -514,7 +514,7 @@ func (w *MigrationWriter) generateAlterTableScripts(schema *models.Schema, model
|
||||
}
|
||||
|
||||
// generateIndexScripts generates CREATE INDEX scripts using templates
|
||||
func (w *MigrationWriter) generateIndexScripts(model *models.Schema, current *models.Schema) ([]MigrationScript, error) {
|
||||
func (w *MigrationWriter) generateIndexScripts(model, current *models.Schema) ([]MigrationScript, error) {
|
||||
scripts := make([]MigrationScript, 0)
|
||||
|
||||
// Build map of current tables
|
||||
@@ -709,7 +709,7 @@ func buildIndexColumnExpressionsFiltered(table *models.Table, index *models.Inde
|
||||
// generateForeignKeyScripts generates ADD CONSTRAINT FOREIGN KEY scripts using templates.
|
||||
// forceRecreate is a set of FK constraint keys (schema.table.name) that must be recreated
|
||||
// even if unchanged, because their referenced PK was dropped and recreated.
|
||||
func (w *MigrationWriter) generateForeignKeyScripts(model *models.Schema, current *models.Schema, forceRecreate map[string]bool) ([]MigrationScript, error) {
|
||||
func (w *MigrationWriter) generateForeignKeyScripts(model, current *models.Schema, forceRecreate map[string]bool) ([]MigrationScript, error) {
|
||||
scripts := make([]MigrationScript, 0)
|
||||
|
||||
// Build map of current tables
|
||||
@@ -787,7 +787,7 @@ func (w *MigrationWriter) generateForeignKeyScripts(model *models.Schema, curren
|
||||
}
|
||||
|
||||
// generateCommentScripts generates COMMENT ON scripts using templates
|
||||
func (w *MigrationWriter) generateCommentScripts(model *models.Schema, current *models.Schema) ([]MigrationScript, error) {
|
||||
func (w *MigrationWriter) generateCommentScripts(model, current *models.Schema) ([]MigrationScript, error) {
|
||||
scripts := make([]MigrationScript, 0)
|
||||
_ = current // TODO: Compare with current schema to only add new/changed comments
|
||||
|
||||
|
||||
@@ -1579,11 +1579,6 @@ func indexOperatorClassForColumn(col *models.Column, indexType, comment string)
|
||||
}
|
||||
}
|
||||
|
||||
// ginOperatorClassForColumn is the GIN-specific form of indexOperatorClassForColumn.
|
||||
func ginOperatorClassForColumn(col *models.Column, comment string) string {
|
||||
return indexOperatorClassForColumn(col, "gin", comment)
|
||||
}
|
||||
|
||||
func operatorClassCompatible(method, baseType string, isArray bool, opClass string) bool {
|
||||
if vectorType, ok := vectorOperatorClasses[opClass]; ok {
|
||||
return !isArray && baseType == vectorType && isVectorIndexMethod(method)
|
||||
@@ -1604,10 +1599,6 @@ func operatorClassCompatible(method, baseType string, isArray bool, opClass stri
|
||||
}
|
||||
}
|
||||
|
||||
func ginOperatorClassCompatible(baseType string, isArray bool, opClass string) bool {
|
||||
return operatorClassCompatible("gin", baseType, isArray, opClass)
|
||||
}
|
||||
|
||||
func isTextGinBaseType(baseType string) bool {
|
||||
switch baseType {
|
||||
case "text", "varchar", "character varying", "char", "character", "string", "citext", "bpchar":
|
||||
@@ -1793,15 +1784,6 @@ func nativeGistBaseType(baseType string) bool {
|
||||
return strings.HasSuffix(baseType, "range") || strings.HasSuffix(baseType, "multirange")
|
||||
}
|
||||
|
||||
func schemaRequiresPGTrgm(schema *models.Schema) bool {
|
||||
for _, ext := range requiredExtensions(schema) {
|
||||
if ext == "pg_trgm" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func resolveIndexColumn(table *models.Table, colName string) (*models.Column, bool) {
|
||||
if table == nil {
|
||||
return nil, false
|
||||
|
||||
@@ -27,7 +27,7 @@ func (w *Writer) WriteDatabase(db *models.Database) error {
|
||||
content := w.databaseToPrisma(db)
|
||||
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0o644)
|
||||
}
|
||||
|
||||
fmt.Print(content)
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
func TestNewWriter(t *testing.T) {
|
||||
opts := &writers.WriterOptions{
|
||||
OutputPath: "/tmp/test.sql",
|
||||
FlattenSchema: false, // Should be forced to true
|
||||
OutputPath: "/tmp/test.sql",
|
||||
FlattenSchema: false, // Should be forced to true
|
||||
}
|
||||
|
||||
writer := NewWriter(opts)
|
||||
|
||||
@@ -57,7 +57,7 @@ func Indent(s string, spaces int) string {
|
||||
|
||||
// IndentWith indents each line of a string with a custom prefix
|
||||
// Usage: {{ .Column.Description | indentWith " " }}
|
||||
func IndentWith(s string, prefix string) string {
|
||||
func IndentWith(s, prefix string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
@@ -93,7 +93,7 @@ func EscapeQuotes(s string) string {
|
||||
// Comment adds comment prefix to a string
|
||||
// Supports: "//" (Go, C++, etc.), "#" (Python, shell), "--" (SQL), "/* */" (block)
|
||||
// Usage: {{ .Table.Description | comment "//" }}
|
||||
func Comment(s string, style string) string {
|
||||
func Comment(s, style string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ import (
|
||||
|
||||
// Get safely gets a value from a map by key
|
||||
// Usage: {{ get .Metadata "key" }}
|
||||
func Get(m interface{}, key interface{}) interface{} {
|
||||
func Get(m, key interface{}) interface{} {
|
||||
return reflectutil.MapGet(m, key)
|
||||
}
|
||||
|
||||
// GetOr safely gets a value from a map with a default fallback
|
||||
// Usage: {{ getOr .Metadata "key" "default" }}
|
||||
func GetOr(m interface{}, key interface{}, defaultValue interface{}) interface{} {
|
||||
func GetOr(m, key, defaultValue interface{}) interface{} {
|
||||
result := Get(m, key)
|
||||
if result == nil {
|
||||
return defaultValue
|
||||
@@ -56,7 +56,7 @@ func SafeIndexOr(slice interface{}, index int, defaultValue interface{}) interfa
|
||||
|
||||
// Has checks if a key exists in a map
|
||||
// Usage: {{ if has .Metadata "key" }}...{{ end }}
|
||||
func Has(m interface{}, key interface{}) bool {
|
||||
func Has(m, key interface{}) bool {
|
||||
v := reflect.ValueOf(m)
|
||||
|
||||
// Dereference pointers
|
||||
@@ -189,7 +189,7 @@ func Omit(m interface{}, keys ...interface{}) map[interface{}]interface{} {
|
||||
|
||||
// SliceContains checks if a slice contains a value
|
||||
// Usage: {{ if sliceContains .Names "admin" }}...{{ end }}
|
||||
func SliceContains(slice interface{}, value interface{}) bool {
|
||||
func SliceContains(slice, value interface{}) bool {
|
||||
v := reflect.ValueOf(slice)
|
||||
v, ok := reflectutil.Deref(v)
|
||||
if !ok {
|
||||
@@ -211,7 +211,7 @@ func SliceContains(slice interface{}, value interface{}) bool {
|
||||
|
||||
// IndexOf returns the index of a value in a slice, or -1 if not found
|
||||
// Usage: {{ $idx := indexOf .Names "admin" }}
|
||||
func IndexOf(slice interface{}, value interface{}) int {
|
||||
func IndexOf(slice, value interface{}) int {
|
||||
v := reflect.ValueOf(slice)
|
||||
v, ok := reflectutil.Deref(v)
|
||||
if !ok {
|
||||
|
||||
@@ -285,7 +285,7 @@ func (w *Writer) generateFilename(data *TemplateData) (string, error) {
|
||||
}
|
||||
|
||||
// writeOutput writes the output to a file or stdout
|
||||
func (w *Writer) writeOutput(content string, outputPath string) error {
|
||||
func (w *Writer) writeOutput(content, outputPath string) error {
|
||||
// If output path is empty, write to stdout
|
||||
if outputPath == "" {
|
||||
fmt.Print(content)
|
||||
@@ -295,13 +295,13 @@ func (w *Writer) writeOutput(content string, outputPath string) error {
|
||||
// Ensure directory exists
|
||||
dir := filepath.Dir(outputPath)
|
||||
if dir != "." && dir != "" {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
return fmt.Errorf("failed to create directory %s: %w", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Write to file
|
||||
if err := os.WriteFile(outputPath, []byte(content), 0644); err != nil {
|
||||
if err := os.WriteFile(outputPath, []byte(content), 0o644); err != nil {
|
||||
return fmt.Errorf("failed to write file %s: %w", outputPath, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@ func TestWriterTableIndexValuesDeterministic(t *testing.T) {
|
||||
outputPath := filepath.Join(outputDir, "accounts.txt")
|
||||
templateBody := "{{range values .Table.Indexes}}{{.Name}}:{{join .Columns \",\"}}\n{{end}}"
|
||||
|
||||
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||
if err := os.MkdirAll(outputDir, 0o755); err != nil {
|
||||
t.Fatalf("create output dir: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(templatePath, []byte(templateBody), 0644); err != nil {
|
||||
if err := os.WriteFile(templatePath, []byte(templateBody), 0o644); err != nil {
|
||||
t.Fatalf("write template: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ func (w *Writer) WriteDatabase(db *models.Database) error {
|
||||
content := w.databaseToTypeORM(db)
|
||||
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
||||
return os.WriteFile(w.options.OutputPath, []byte(content), 0o644)
|
||||
}
|
||||
|
||||
fmt.Print(content)
|
||||
|
||||
@@ -55,7 +55,7 @@ func (w *Writer) WriteTable(table *models.Table) error {
|
||||
// writeOutput writes the content to file or stdout
|
||||
func (w *Writer) writeOutput(data []byte) error {
|
||||
if w.options.OutputPath != "" {
|
||||
return os.WriteFile(w.options.OutputPath, data, 0644)
|
||||
return os.WriteFile(w.options.OutputPath, data, 0o644)
|
||||
}
|
||||
|
||||
// Print to stdout
|
||||
|
||||
Reference in New Issue
Block a user