summaryrefslogtreecommitdiff
path: root/vendor/github.com/uptrace/bun/migrate/sqlschema/database.go
blob: cdc5b2d507d622847f1835677d03c2e31aaf5afb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package sqlschema

import (
	"slices"
	"strings"

	"github.com/uptrace/bun/schema"
	orderedmap "github.com/wk8/go-ordered-map/v2"
)

type Database interface {
	GetTables() *orderedmap.OrderedMap[string, Table]
	GetForeignKeys() map[ForeignKey]string
}

var _ Database = (*BaseDatabase)(nil)

// BaseDatabase is a base database definition.
//
// Dialects and only dialects can use it to implement the Database interface.
// Other packages must use the Database interface.
type BaseDatabase struct {
	Tables      *orderedmap.OrderedMap[string, Table]
	ForeignKeys map[ForeignKey]string
}

func (ds BaseDatabase) GetTables() *orderedmap.OrderedMap[string, Table] {
	return ds.Tables
}

func (ds BaseDatabase) GetForeignKeys() map[ForeignKey]string {
	return ds.ForeignKeys
}

type ForeignKey struct {
	From ColumnReference
	To   ColumnReference
}

func NewColumnReference(tableName string, columns ...string) ColumnReference {
	return ColumnReference{
		TableName: tableName,
		Column:    NewColumns(columns...),
	}
}

func (fk ForeignKey) DependsOnTable(tableName string) bool {
	return fk.From.TableName == tableName || fk.To.TableName == tableName
}

func (fk ForeignKey) DependsOnColumn(tableName string, column string) bool {
	return fk.DependsOnTable(tableName) &&
		(fk.From.Column.Contains(column) || fk.To.Column.Contains(column))
}

// Columns is a hashable representation of []string used to define schema constraints that depend on multiple columns.
// Although having duplicated column references in these constraints is illegal, Columns neither validates nor enforces this constraint on the caller.
type Columns string

// NewColumns creates a composite column from a slice of column names.
func NewColumns(columns ...string) Columns {
	slices.Sort(columns)
	return Columns(strings.Join(columns, ","))
}

func (c *Columns) String() string {
	return string(*c)
}

func (c *Columns) AppendQuery(fmter schema.Formatter, b []byte) ([]byte, error) {
	return schema.Safe(*c).AppendQuery(fmter, b)
}

// Split returns a slice of column names that make up the composite.
func (c *Columns) Split() []string {
	return strings.Split(c.String(), ",")
}

// ContainsColumns checks that columns in "other" are a subset of current colums.
func (c *Columns) ContainsColumns(other Columns) bool {
	columns := c.Split()
Outer:
	for _, check := range other.Split() {
		for _, column := range columns {
			if check == column {
				continue Outer
			}
		}
		return false
	}
	return true
}

// Contains checks that a composite column contains the current column.
func (c *Columns) Contains(other string) bool {
	return c.ContainsColumns(Columns(other))
}

// Replace renames a column if it is part of the composite.
// If a composite consists of multiple columns, only one column will be renamed.
func (c *Columns) Replace(oldColumn, newColumn string) bool {
	columns := c.Split()
	for i, column := range columns {
		if column == oldColumn {
			columns[i] = newColumn
			*c = NewColumns(columns...)
			return true
		}
	}
	return false
}

// Unique represents a unique constraint defined on 1 or more columns.
type Unique struct {
	Name    string
	Columns Columns
}

// Equals checks that two unique constraint are the same, assuming both are defined for the same table.
func (u Unique) Equals(other Unique) bool {
	return u.Columns == other.Columns
}

type ColumnReference struct {
	TableName string
	Column    Columns
}